blob: 027e75d6521a6e271eb88c77f59a653e884ad028 [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"
Myung Bae3f95a272024-03-13 07:32:02 -070020#include "utils/chassis_utils.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080021#include "utils/dbus_utils.hpp"
22#include "utils/json_utils.hpp"
23#include "utils/query_param.hpp"
Janet Adkins1516c212024-08-14 13:22:41 -050024#include "utils/sensor_utils.hpp"
Ed Tanous0ec8b832022-03-14 14:56:47 -070025
Ed Tanousd7857202025-01-28 15:32:26 -080026#include <asm-generic/errno.h>
27
28#include <boost/beast/http/status.hpp>
29#include <boost/beast/http/verb.hpp>
George Liue99073f2022-12-09 11:06:16 +080030#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070031#include <boost/url/format.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080032#include <boost/url/url.hpp>
33#include <nlohmann/json.hpp>
34#include <sdbusplus/message/native_types.hpp>
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +020035#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050036
Ed Tanousd7857202025-01-28 15:32:26 -080037#include <algorithm>
George Liu7a1dbc42022-12-07 16:03:22 +080038#include <array>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050039#include <cmath>
Ed Tanousd7857202025-01-28 15:32:26 -080040#include <cstddef>
41#include <cstdint>
42#include <functional>
Nan Zhoufe04d492022-06-22 17:10:41 +000043#include <iterator>
44#include <map>
Ed Tanousd7857202025-01-28 15:32:26 -080045#include <memory>
46#include <optional>
Ed Tanous3544d2a2023-08-06 18:12:20 -070047#include <ranges>
Nan Zhoufe04d492022-06-22 17:10:41 +000048#include <set>
Ed Tanousd7857202025-01-28 15:32:26 -080049#include <span>
Ed Tanous18f8f602023-07-18 10:07:23 -070050#include <string>
George Liu7a1dbc42022-12-07 16:03:22 +080051#include <string_view>
Ed Tanousd7857202025-01-28 15:32:26 -080052#include <unordered_map>
Ed Tanousb5a76932020-09-29 16:16:58 -070053#include <utility>
Ed Tanousabf2add2019-01-22 16:40:12 -080054#include <variant>
Ed Tanousd7857202025-01-28 15:32:26 -080055#include <vector>
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010056
Ed Tanous1abe55e2018-09-05 08:30:59 -070057namespace redfish
58{
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010059
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020060namespace sensors
61{
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020062
Ed Tanous02da7c52022-02-27 00:09:02 -080063// clang-format off
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020064namespace dbus
65{
Ed Tanouscf9e4172022-12-21 09:30:16 -080066constexpr auto powerPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080067 "/xyz/openbmc_project/sensors/voltage",
68 "/xyz/openbmc_project/sensors/power"
69});
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000070
Ed Tanous25b54db2024-04-17 15:40:31 -070071constexpr auto getSensorPaths(){
72 if constexpr(BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM){
73 return std::to_array<std::string_view>({
74 "/xyz/openbmc_project/sensors/power",
75 "/xyz/openbmc_project/sensors/current",
76 "/xyz/openbmc_project/sensors/airflow",
77 "/xyz/openbmc_project/sensors/humidity",
78 "/xyz/openbmc_project/sensors/voltage",
79 "/xyz/openbmc_project/sensors/fan_tach",
80 "/xyz/openbmc_project/sensors/temperature",
81 "/xyz/openbmc_project/sensors/fan_pwm",
82 "/xyz/openbmc_project/sensors/altitude",
83 "/xyz/openbmc_project/sensors/energy",
Zev Weiss44914192025-03-11 07:59:30 +000084 "/xyz/openbmc_project/sensors/liquidflow",
85 "/xyz/openbmc_project/sensors/pressure",
Ed Tanous25b54db2024-04-17 15:40:31 -070086 "/xyz/openbmc_project/sensors/utilization"});
87 } else {
88 return std::to_array<std::string_view>({"/xyz/openbmc_project/sensors/power",
89 "/xyz/openbmc_project/sensors/current",
90 "/xyz/openbmc_project/sensors/airflow",
91 "/xyz/openbmc_project/sensors/humidity",
92 "/xyz/openbmc_project/sensors/utilization"});
93}
94}
95
96constexpr auto sensorPaths = getSensorPaths();
Ed Tanous02da7c52022-02-27 00:09:02 -080097
Ed Tanouscf9e4172022-12-21 09:30:16 -080098constexpr auto thermalPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080099 "/xyz/openbmc_project/sensors/fan_tach",
100 "/xyz/openbmc_project/sensors/temperature",
101 "/xyz/openbmc_project/sensors/fan_pwm"
102});
103
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000104} // namespace dbus
Ed Tanous02da7c52022-02-27 00:09:02 -0800105// clang-format on
106
Janet Adkins0c728b42024-08-29 11:09:10 -0500107constexpr std::string_view powerNodeStr = sensor_utils::chassisSubNodeToString(
108 sensor_utils::ChassisSubNode::powerNode);
109constexpr std::string_view sensorsNodeStr =
110 sensor_utils::chassisSubNodeToString(
111 sensor_utils::ChassisSubNode::sensorsNode);
112constexpr std::string_view thermalNodeStr =
113 sensor_utils::chassisSubNodeToString(
114 sensor_utils::ChassisSubNode::thermalNode);
115
Ed Tanouscf9e4172022-12-21 09:30:16 -0800116using sensorPair =
117 std::pair<std::string_view, std::span<const std::string_view>>;
Ed Tanous02da7c52022-02-27 00:09:02 -0800118static constexpr std::array<sensorPair, 3> paths = {
Janet Adkins0c728b42024-08-29 11:09:10 -0500119 {{sensors::powerNodeStr, dbus::powerPaths},
120 {sensors::sensorsNodeStr, dbus::sensorPaths},
121 {sensors::thermalNodeStr, dbus::thermalPaths}}};
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000122
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200123} // namespace sensors
124
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100125/**
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200126 * SensorsAsyncResp
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100127 * Gathers data needed for response processing after async calls are done
128 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700129class SensorsAsyncResp
130{
131 public:
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200132 using DataCompleteCb = std::function<void(
133 const boost::beast::http::status status,
Nan Zhoufe04d492022-06-22 17:10:41 +0000134 const std::map<std::string, std::string>& uriToDbus)>;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200135
136 struct SensorData
137 {
Ed Tanousf836c1d2024-09-06 16:05:11 -0700138 std::string name;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200139 std::string uri;
Ed Tanousf836c1d2024-09-06 16:05:11 -0700140 std::string dbusPath;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200141 };
142
Ed Tanous8a592812022-06-04 09:06:59 -0700143 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800144 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800145 std::span<const std::string_view> typesIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800146 std::string_view subNode) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400147 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
148 chassisSubNode(subNode), efficientExpand(false)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500149 {}
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200150
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200151 // Store extra data about sensor mapping and return it in callback
Ed Tanous8a592812022-06-04 09:06:59 -0700152 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800153 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800154 std::span<const std::string_view> typesIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800155 std::string_view subNode,
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200156 DataCompleteCb&& creationComplete) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400157 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
158 chassisSubNode(subNode), efficientExpand(false),
159 metadata{std::vector<SensorData>()},
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200160 dataComplete{std::move(creationComplete)}
161 {}
162
Nan Zhou928fefb2022-03-28 08:45:00 -0700163 // sensor collections expand
Ed Tanous8a592812022-06-04 09:06:59 -0700164 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
Nan Zhou928fefb2022-03-28 08:45:00 -0700165 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800166 std::span<const std::string_view> typesIn,
Ed Tanous8a592812022-06-04 09:06:59 -0700167 const std::string_view& subNode, bool efficientExpandIn) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400168 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
169 chassisSubNode(subNode), efficientExpand(efficientExpandIn)
Nan Zhou928fefb2022-03-28 08:45:00 -0700170 {}
171
Ed Tanous1abe55e2018-09-05 08:30:59 -0700172 ~SensorsAsyncResp()
173 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800174 if (asyncResp->res.result() ==
175 boost::beast::http::status::internal_server_error)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700176 {
177 // Reset the json object to clear out any data that made it in
178 // before the error happened todo(ed) handle error condition with
179 // proper code
zhanghch058d1b46d2021-04-01 11:18:24 +0800180 asyncResp->res.jsonValue = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700181 }
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200182
183 if (dataComplete && metadata)
184 {
Nan Zhoufe04d492022-06-22 17:10:41 +0000185 std::map<std::string, std::string> map;
zhanghch058d1b46d2021-04-01 11:18:24 +0800186 if (asyncResp->res.result() == boost::beast::http::status::ok)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200187 {
188 for (auto& sensor : *metadata)
189 {
Ed Tanousc1d019a2022-08-06 09:36:06 -0700190 map.emplace(sensor.uri, sensor.dbusPath);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200191 }
192 }
zhanghch058d1b46d2021-04-01 11:18:24 +0800193 dataComplete(asyncResp->res.result(), map);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200194 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700195 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100196
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800197 SensorsAsyncResp(const SensorsAsyncResp&) = delete;
198 SensorsAsyncResp(SensorsAsyncResp&&) = delete;
199 SensorsAsyncResp& operator=(const SensorsAsyncResp&) = delete;
200 SensorsAsyncResp& operator=(SensorsAsyncResp&&) = delete;
201
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200202 void addMetadata(const nlohmann::json& sensorObject,
Ed Tanousc1d019a2022-08-06 09:36:06 -0700203 const std::string& dbusPath)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200204 {
Ed Tanous82b286f2025-05-06 13:29:48 -0700205 if (!metadata)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200206 {
Ed Tanous82b286f2025-05-06 13:29:48 -0700207 return;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200208 }
Ed Tanous82b286f2025-05-06 13:29:48 -0700209 const auto nameIt = sensorObject.find("Name");
210 if (nameIt != sensorObject.end())
211 {
212 return;
213 }
214 const auto idIt = sensorObject.find("@odata.id");
215 if (idIt != sensorObject.end())
216 {
217 return;
218 }
219 const std::string* name = nameIt->get_ptr<const std::string*>();
220 if (name == nullptr)
221 {
222 return;
223 }
224 const std::string* id = idIt->get_ptr<const std::string*>();
225 if (id == nullptr)
226 {
227 return;
228 }
229 metadata->emplace_back(SensorData{*name, *id, dbusPath});
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200230 }
231
232 void updateUri(const std::string& name, const std::string& uri)
233 {
234 if (metadata)
235 {
236 for (auto& sensor : *metadata)
237 {
238 if (sensor.name == name)
239 {
240 sensor.uri = uri;
241 }
242 }
243 }
244 }
245
zhanghch058d1b46d2021-04-01 11:18:24 +0800246 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200247 const std::string chassisId;
Ed Tanouscf9e4172022-12-21 09:30:16 -0800248 const std::span<const std::string_view> types;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200249 const std::string chassisSubNode;
Nan Zhou928fefb2022-03-28 08:45:00 -0700250 const bool efficientExpand;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200251
252 private:
253 std::optional<std::vector<SensorData>> metadata;
254 DataCompleteCb dataComplete;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100255};
256
Janet Adkinsc9563602024-08-28 11:37:46 -0500257using InventoryItem = sensor_utils::InventoryItem;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500258
259/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530260 * @brief Get objects with connection necessary for sensors
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200261 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100262 * @param sensorNames Sensors retrieved from chassis
263 * @param callback Callback for processing gathered connections
264 */
265template <typename Callback>
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530266void getObjectsWithConnection(
Ed Tanous81ce6092020-12-17 16:54:55 +0000267 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +0000268 const std::shared_ptr<std::set<std::string>>& sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530269 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700270{
Ed Tanous62598e32023-07-17 17:06:25 -0700271 BMCWEB_LOG_DEBUG("getObjectsWithConnection enter");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700272 const std::string path = "/xyz/openbmc_project/sensors";
George Liue99073f2022-12-09 11:06:16 +0800273 constexpr std::array<std::string_view, 1> interfaces = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700274 "xyz.openbmc_project.Sensor.Value"};
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100275
George Liue99073f2022-12-09 11:06:16 +0800276 // Make call to ObjectMapper to find all sensors objects
277 dbus::utility::getSubTree(
278 path, 2, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700279 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
George Liue99073f2022-12-09 11:06:16 +0800280 sensorNames](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700281 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400282 // Response handler for parsing objects subtree
283 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler enter");
284 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700285 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400286 messages::internalError(sensorsAsyncResp->asyncResp->res);
287 BMCWEB_LOG_ERROR(
288 "getObjectsWithConnection resp_handler: Dbus error {}", ec);
289 return;
290 }
291
292 BMCWEB_LOG_DEBUG("Found {} subtrees", subtree.size());
293
294 // Make unique list of connections only for requested sensor types
295 // and found in the chassis
296 std::set<std::string> connections;
297 std::set<std::pair<std::string, std::string>> objectsWithConnection;
298
299 BMCWEB_LOG_DEBUG("sensorNames list count: {}", sensorNames->size());
300 for (const std::string& tsensor : *sensorNames)
301 {
302 BMCWEB_LOG_DEBUG("Sensor to find: {}", tsensor);
303 }
304
305 for (const std::pair<std::string,
306 std::vector<std::pair<
307 std::string, std::vector<std::string>>>>&
308 object : subtree)
309 {
Ed Tanous3d158642025-05-12 14:20:49 -0700310 if (sensorNames->contains(object.first))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700311 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400312 for (const std::pair<std::string, std::vector<std::string>>&
313 objData : object.second)
314 {
315 BMCWEB_LOG_DEBUG("Adding connection: {}",
316 objData.first);
317 connections.insert(objData.first);
318 objectsWithConnection.insert(
319 std::make_pair(object.first, objData.first));
320 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700321 }
322 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400323 BMCWEB_LOG_DEBUG("Found {} connections", connections.size());
324 callback(std::move(connections), std::move(objectsWithConnection));
325 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler exit");
326 });
Ed Tanous62598e32023-07-17 17:06:25 -0700327 BMCWEB_LOG_DEBUG("getObjectsWithConnection exit");
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530328}
329
330/**
331 * @brief Create connections necessary for sensors
332 * @param SensorsAsyncResp Pointer to object holding response data
333 * @param sensorNames Sensors retrieved from chassis
334 * @param callback Callback for processing gathered connections
335 */
336template <typename Callback>
Ed Tanousdaadfb22024-12-20 09:25:54 -0800337void getConnections(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
338 const std::shared_ptr<std::set<std::string>>& sensorNames,
Nan Zhoufe04d492022-06-22 17:10:41 +0000339 Callback&& callback)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530340{
341 auto objectsWithConnectionCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -0700342 [callback = std::forward<Callback>(callback)](
343 const std::set<std::string>& connections,
344 const std::set<std::pair<std::string, std::string>>&
345 /*objectsWithConnection*/) { callback(connections); };
Ed Tanous81ce6092020-12-17 16:54:55 +0000346 getObjectsWithConnection(sensorsAsyncResp, sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530347 std::move(objectsWithConnectionCb));
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100348}
349
350/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700351 * @brief Shrinks the list of sensors for processing
352 * @param SensorsAysncResp The class holding the Redfish response
353 * @param allSensors A list of all the sensors associated to the
354 * chassis element (i.e. baseboard, front panel, etc...)
355 * @param activeSensors A list that is a reduction of the incoming
356 * allSensors list. Eliminate Thermal sensors when a Power request is
357 * made, and eliminate Power sensors when a Thermal request is made.
358 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000359inline void reduceSensorList(
Ed Tanous7f1cc262022-08-09 13:33:57 -0700360 crow::Response& res, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800361 std::span<const std::string_view> sensorTypes,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700362 const std::vector<std::string>* allSensors,
Nan Zhoufe04d492022-06-22 17:10:41 +0000363 const std::shared_ptr<std::set<std::string>>& activeSensors)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700364{
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700365 if ((allSensors == nullptr) || (activeSensors == nullptr))
366 {
Ed Tanous7f1cc262022-08-09 13:33:57 -0700367 messages::resourceNotFound(res, chassisSubNode,
Janet Adkins0c728b42024-08-29 11:09:10 -0500368 chassisSubNode == sensors::thermalNodeStr
Ed Tanous7f1cc262022-08-09 13:33:57 -0700369 ? "Temperatures"
370 : "Voltages");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700371
372 return;
373 }
374 if (allSensors->empty())
375 {
376 // Nothing to do, the activeSensors object is also empty
377 return;
378 }
379
Ed Tanous7f1cc262022-08-09 13:33:57 -0700380 for (std::string_view type : sensorTypes)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700381 {
382 for (const std::string& sensor : *allSensors)
383 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700384 if (sensor.starts_with(type))
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700385 {
386 activeSensors->emplace(sensor);
387 }
388 }
389 }
390}
391
Ed Tanous7f1cc262022-08-09 13:33:57 -0700392/*
393 *Populates the top level collection for a given subnode. Populates
394 *SensorCollection, Power, or Thermal schemas.
395 *
396 * */
397inline void populateChassisNode(nlohmann::json& jsonValue,
398 std::string_view chassisSubNode)
399{
Janet Adkins0c728b42024-08-29 11:09:10 -0500400 if (chassisSubNode == sensors::powerNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700401 {
402 jsonValue["@odata.type"] = "#Power.v1_5_2.Power";
403 }
Janet Adkins0c728b42024-08-29 11:09:10 -0500404 else if (chassisSubNode == sensors::thermalNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700405 {
406 jsonValue["@odata.type"] = "#Thermal.v1_4_0.Thermal";
407 jsonValue["Fans"] = nlohmann::json::array();
408 jsonValue["Temperatures"] = nlohmann::json::array();
409 }
Janet Adkins0c728b42024-08-29 11:09:10 -0500410 else if (chassisSubNode == sensors::sensorsNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700411 {
412 jsonValue["@odata.type"] = "#SensorCollection.SensorCollection";
413 jsonValue["Description"] = "Collection of Sensors for this Chassis";
414 jsonValue["Members"] = nlohmann::json::array();
415 jsonValue["Members@odata.count"] = 0;
416 }
417
Janet Adkins0c728b42024-08-29 11:09:10 -0500418 if (chassisSubNode != sensors::sensorsNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700419 {
420 jsonValue["Id"] = chassisSubNode;
421 }
422 jsonValue["Name"] = chassisSubNode;
423}
424
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700425/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100426 * @brief Retrieves requested chassis sensors and redundancy data from DBus .
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200427 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100428 * @param callback Callback for next step in gathered sensor processing
429 */
430template <typename Callback>
Ed Tanous7f1cc262022-08-09 13:33:57 -0700431void getChassis(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
432 std::string_view chassisId, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800433 std::span<const std::string_view> sensorTypes,
434 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700435{
Ed Tanous62598e32023-07-17 17:06:25 -0700436 BMCWEB_LOG_DEBUG("getChassis enter");
George Liu7a1dbc42022-12-07 16:03:22 +0800437
438 // Get the Chassis Collection
439 dbus::utility::getSubTreePaths(
Myung Bae3f95a272024-03-13 07:32:02 -0700440 "/xyz/openbmc_project/inventory", 0, chassisInterfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700441 [callback = std::forward<Callback>(callback), asyncResp,
Ed Tanous7f1cc262022-08-09 13:33:57 -0700442 chassisIdStr{std::string(chassisId)},
Ed Tanous4e0d8782024-09-06 15:16:41 -0700443 chassisSubNode{std::string(chassisSubNode)},
444 sensorTypes](const boost::system::error_code& ec,
445 const dbus::utility::MapperGetSubTreePathsResponse&
446 chassisPaths) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400447 BMCWEB_LOG_DEBUG("getChassis respHandler enter");
448 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700449 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400450 BMCWEB_LOG_ERROR("getChassis respHandler DBUS error: {}", ec);
451 messages::internalError(asyncResp->res);
452 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700453 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400454 const std::string* chassisPath = nullptr;
455 for (const std::string& chassis : chassisPaths)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700456 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400457 sdbusplus::message::object_path path(chassis);
458 std::string chassisName = path.filename();
459 if (chassisName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700460 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400461 BMCWEB_LOG_ERROR("Failed to find '/' in {}", chassis);
462 continue;
463 }
464 if (chassisName == chassisIdStr)
465 {
466 chassisPath = &chassis;
467 break;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700468 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700469 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400470 if (chassisPath == nullptr)
471 {
472 messages::resourceNotFound(asyncResp->res, "Chassis",
473 chassisIdStr);
474 return;
475 }
476 populateChassisNode(asyncResp->res.jsonValue, chassisSubNode);
477
478 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
479 "/redfish/v1/Chassis/{}/{}", chassisIdStr, chassisSubNode);
480
481 // Get the list of all sensors for this Chassis element
482 std::string sensorPath = *chassisPath + "/all_sensors";
483 dbus::utility::getAssociationEndPoints(
Ed Tanous4e0d8782024-09-06 15:16:41 -0700484 sensorPath, [asyncResp, chassisSubNode, sensorTypes,
485 callback = std::forward<Callback>(callback)](
486 const boost::system::error_code& ec2,
487 const dbus::utility::MapperEndPoints&
488 nodeSensorList) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400489 if (ec2)
490 {
491 if (ec2.value() != EBADR)
492 {
493 messages::internalError(asyncResp->res);
494 return;
495 }
496 }
497 const std::shared_ptr<std::set<std::string>>
498 culledSensorList =
499 std::make_shared<std::set<std::string>>();
500 reduceSensorList(asyncResp->res, chassisSubNode,
501 sensorTypes, &nodeSensorList,
502 culledSensorList);
503 BMCWEB_LOG_DEBUG("Finishing with {}",
504 culledSensorList->size());
505 callback(culledSensorList);
506 });
George Liu7a1dbc42022-12-07 16:03:22 +0800507 });
Ed Tanous62598e32023-07-17 17:06:25 -0700508 BMCWEB_LOG_DEBUG("getChassis exit");
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100509}
510
511/**
Ed Tanous1d7c0052022-08-09 12:32:26 -0700512 * @brief Builds a json sensor representation of a sensor.
513 * @param sensorName The name of the sensor to be built
514 * @param sensorType The type (temperature, fan_tach, etc) of the sensor to
515 * build
Ed Tanous8ece0e42024-01-02 13:16:50 -0800516 * @param chassisSubNode The subnode (thermal, sensor, etc) of the sensor
Ed Tanous1d7c0052022-08-09 12:32:26 -0700517 * @param interfacesDict A dictionary of the interfaces and properties of said
518 * interfaces to be built from
519 * @param sensorJson The json object to fill
520 * @param inventoryItem D-Bus inventory item associated with the sensor. Will
521 * be nullptr if no associated inventory item was found.
522 */
523inline void objectInterfacesToJson(
524 const std::string& sensorName, const std::string& sensorType,
Janet Adkins0c728b42024-08-29 11:09:10 -0500525 const sensor_utils::ChassisSubNode chassisSubNode,
Michael Shen80f79a42023-08-24 13:41:53 +0000526 const dbus::utility::DBusInterfacesMap& interfacesDict,
Ed Tanous1d7c0052022-08-09 12:32:26 -0700527 nlohmann::json& sensorJson, InventoryItem* inventoryItem)
528{
Ed Tanous1d7c0052022-08-09 12:32:26 -0700529 for (const auto& [interface, valuesDict] : interfacesDict)
530 {
Janet Adkinsc9563602024-08-28 11:37:46 -0500531 sensor_utils::objectPropertiesToJson(
532 sensorName, sensorType, chassisSubNode, valuesDict, sensorJson,
533 inventoryItem);
Ed Tanous1d7c0052022-08-09 12:32:26 -0700534 }
Ed Tanous62598e32023-07-17 17:06:25 -0700535 BMCWEB_LOG_DEBUG("Added sensor {}", sensorName);
Ed Tanous1d7c0052022-08-09 12:32:26 -0700536}
537
Ed Tanousb5a76932020-09-29 16:16:58 -0700538inline void populateFanRedundancy(
539 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
James Feist8bd25cc2019-03-15 15:14:00 -0700540{
George Liue99073f2022-12-09 11:06:16 +0800541 constexpr std::array<std::string_view, 1> interfaces = {
542 "xyz.openbmc_project.Control.FanRedundancy"};
543 dbus::utility::getSubTree(
544 "/xyz/openbmc_project/control", 2, interfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800545 [sensorsAsyncResp](
George Liue99073f2022-12-09 11:06:16 +0800546 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800547 const dbus::utility::MapperGetSubTreeResponse& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400548 if (ec)
James Feist8bd25cc2019-03-15 15:14:00 -0700549 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400550 return; // don't have to have this interface
James Feist8bd25cc2019-03-15 15:14:00 -0700551 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400552 for (const std::pair<std::string, dbus::utility::MapperServiceMap>&
553 pathPair : resp)
554 {
555 const std::string& path = pathPair.first;
556 const dbus::utility::MapperServiceMap& objDict =
557 pathPair.second;
558 if (objDict.empty())
James Feist8bd25cc2019-03-15 15:14:00 -0700559 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400560 continue; // this should be impossible
James Feist8bd25cc2019-03-15 15:14:00 -0700561 }
562
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400563 const std::string& owner = objDict.begin()->first;
564 dbus::utility::getAssociationEndPoints(
565 path + "/chassis",
566 [path, owner, sensorsAsyncResp](
567 const boost::system::error_code& ec2,
568 const dbus::utility::MapperEndPoints& endpoints) {
569 if (ec2)
James Feist8bd25cc2019-03-15 15:14:00 -0700570 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400571 return; // if they don't have an association we
572 // can't tell what chassis is
James Feist8bd25cc2019-03-15 15:14:00 -0700573 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400574 auto found = std::ranges::find_if(
575 endpoints,
576 [sensorsAsyncResp](const std::string& entry) {
577 return entry.find(
578 sensorsAsyncResp->chassisId) !=
579 std::string::npos;
580 });
581
582 if (found == endpoints.end())
James Feist8bd25cc2019-03-15 15:14:00 -0700583 {
584 return;
585 }
Ed Tanousdeae6a72024-11-11 21:58:57 -0800586 dbus::utility::getAllProperties(
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400587 *crow::connections::systemBus, owner, path,
588 "xyz.openbmc_project.Control.FanRedundancy",
589 [path, sensorsAsyncResp](
590 const boost::system::error_code& ec3,
591 const dbus::utility::DBusPropertiesMap& ret) {
592 if (ec3)
593 {
594 return; // don't have to have this
595 // interface
596 }
James Feist8bd25cc2019-03-15 15:14:00 -0700597
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400598 const uint8_t* allowedFailures = nullptr;
599 const std::vector<std::string>* collection =
600 nullptr;
601 const std::string* status = nullptr;
James Feist8bd25cc2019-03-15 15:14:00 -0700602
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400603 const bool success =
604 sdbusplus::unpackPropertiesNoThrow(
605 dbus_utils::UnpackErrorPrinter(), ret,
606 "AllowedFailures", allowedFailures,
607 "Collection", collection, "Status",
608 status);
James Feist8bd25cc2019-03-15 15:14:00 -0700609
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400610 if (!success)
611 {
612 messages::internalError(
613 sensorsAsyncResp->asyncResp->res);
614 return;
615 }
616
617 if (allowedFailures == nullptr ||
618 collection == nullptr || status == nullptr)
619 {
620 BMCWEB_LOG_ERROR(
621 "Invalid redundancy interface");
622 messages::internalError(
623 sensorsAsyncResp->asyncResp->res);
624 return;
625 }
626
627 sdbusplus::message::object_path objectPath(
628 path);
629 std::string name = objectPath.filename();
630 if (name.empty())
631 {
632 // this should be impossible
633 messages::internalError(
634 sensorsAsyncResp->asyncResp->res);
635 return;
636 }
637 std::ranges::replace(name, '_', ' ');
638
639 std::string health;
640
641 if (status->ends_with("Full"))
642 {
643 health = "OK";
644 }
645 else if (status->ends_with("Degraded"))
646 {
647 health = "Warning";
648 }
649 else
650 {
651 health = "Critical";
652 }
653 nlohmann::json::array_t redfishCollection;
654 const auto& fanRedfish =
655 sensorsAsyncResp->asyncResp->res
656 .jsonValue["Fans"];
657 for (const std::string& item : *collection)
658 {
659 sdbusplus::message::object_path itemPath(
660 item);
661 std::string itemName = itemPath.filename();
662 if (itemName.empty())
663 {
664 continue;
665 }
666 /*
667 todo(ed): merge patch that fixes the names
668 std::replace(itemName.begin(),
669 itemName.end(), '_', ' ');*/
670 auto schemaItem = std::ranges::find_if(
671 fanRedfish,
672 [itemName](const nlohmann::json& fan) {
673 return fan["Name"] == itemName;
674 });
675 if (schemaItem != fanRedfish.end())
676 {
677 nlohmann::json::object_t collectionId;
678 collectionId["@odata.id"] =
679 (*schemaItem)["@odata.id"];
680 redfishCollection.emplace_back(
681 std::move(collectionId));
682 }
683 else
684 {
685 BMCWEB_LOG_ERROR(
686 "failed to find fan in schema");
687 messages::internalError(
688 sensorsAsyncResp->asyncResp->res);
689 return;
690 }
691 }
692
693 size_t minNumNeeded =
694 collection->empty()
695 ? 0
696 : collection->size() - *allowedFailures;
697 nlohmann::json& jResp =
698 sensorsAsyncResp->asyncResp->res
699 .jsonValue["Redundancy"];
700
701 nlohmann::json::object_t redundancy;
702 boost::urls::url url = boost::urls::format(
703 "/redfish/v1/Chassis/{}/{}",
704 sensorsAsyncResp->chassisId,
705 sensorsAsyncResp->chassisSubNode);
706 url.set_fragment(
707 ("/Redundancy"_json_pointer / jResp.size())
708 .to_string());
709 redundancy["@odata.id"] = std::move(url);
710 redundancy["@odata.type"] =
711 "#Redundancy.v1_3_2.Redundancy";
712 redundancy["MinNumNeeded"] = minNumNeeded;
713 redundancy["Mode"] =
714 redundancy::RedundancyType::NPlusM;
715 redundancy["Name"] = name;
716 redundancy["RedundancySet"] = redfishCollection;
717 redundancy["Status"]["Health"] = health;
718 redundancy["Status"]["State"] =
719 resource::State::Enabled;
720
721 jResp.emplace_back(std::move(redundancy));
722 });
723 });
724 }
725 });
James Feist8bd25cc2019-03-15 15:14:00 -0700726}
727
Patrick Williams504af5a2025-02-03 14:29:03 -0500728inline void sortJSONResponse(
729 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700730{
zhanghch058d1b46d2021-04-01 11:18:24 +0800731 nlohmann::json& response = sensorsAsyncResp->asyncResp->res.jsonValue;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700732 std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
Janet Adkins0c728b42024-08-29 11:09:10 -0500733 if (sensorsAsyncResp->chassisSubNode == sensors::powerNodeStr)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700734 {
735 sensorHeaders = {"Voltages", "PowerSupplies"};
736 }
737 for (const std::string& sensorGroup : sensorHeaders)
738 {
739 nlohmann::json::iterator entry = response.find(sensorGroup);
Ed Tanous4e196b92024-09-27 17:45:09 -0700740 if (entry == response.end())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700741 {
Ed Tanous4e196b92024-09-27 17:45:09 -0700742 continue;
743 }
744 nlohmann::json::array_t* arr =
745 entry->get_ptr<nlohmann::json::array_t*>();
746 if (arr == nullptr)
747 {
748 continue;
749 }
750 json_util::sortJsonArrayByKey(*arr, "Name");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700751
Ed Tanous4e196b92024-09-27 17:45:09 -0700752 // add the index counts to the end of each entry
753 size_t count = 0;
754 for (nlohmann::json& sensorJson : *entry)
755 {
756 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
757 if (odata == sensorJson.end())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700758 {
Ed Tanous4e196b92024-09-27 17:45:09 -0700759 continue;
760 }
Ed Tanous82b286f2025-05-06 13:29:48 -0700761 const auto nameIt = sensorJson.find("Name");
762 if (nameIt == sensorJson.end())
Ed Tanous4e196b92024-09-27 17:45:09 -0700763 {
Ed Tanous82b286f2025-05-06 13:29:48 -0700764 continue;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700765 }
Ed Tanous82b286f2025-05-06 13:29:48 -0700766 std::string* value = odata->get_ptr<std::string*>();
767 if (value == nullptr)
768 {
769 continue;
770 }
771 const std::string* name = nameIt->get_ptr<const std::string*>();
772 if (name == nullptr)
773 {
774 continue;
775 }
776 *value += "/" + std::to_string(count);
777 sensorJson["MemberId"] = std::to_string(count);
778 count++;
779 sensorsAsyncResp->updateUri(*name, *value);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700780 }
781 }
782}
783
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100784/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500785 * @brief Finds the inventory item with the specified object path.
786 * @param inventoryItems D-Bus inventory items associated with sensors.
787 * @param invItemObjPath D-Bus object path of inventory item.
788 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500789 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000790inline InventoryItem* findInventoryItem(
Ed Tanousb5a76932020-09-29 16:16:58 -0700791 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500792 const std::string& invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500793{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500794 for (InventoryItem& inventoryItem : *inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500795 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500796 if (inventoryItem.objectPath == invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500797 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500798 return &inventoryItem;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500799 }
800 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500801 return nullptr;
802}
803
804/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500805 * @brief Finds the inventory item associated with the specified sensor.
806 * @param inventoryItems D-Bus inventory items associated with sensors.
807 * @param sensorObjPath D-Bus object path of sensor.
808 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500809 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000810inline InventoryItem* findInventoryItemForSensor(
Ed Tanousb5a76932020-09-29 16:16:58 -0700811 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500812 const std::string& sensorObjPath)
813{
814 for (InventoryItem& inventoryItem : *inventoryItems)
815 {
Ed Tanousdb0d36e2023-06-30 10:37:05 -0700816 if (inventoryItem.sensors.contains(sensorObjPath))
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500817 {
818 return &inventoryItem;
819 }
820 }
821 return nullptr;
822}
823
824/**
Anthony Wilsond5005492019-07-31 16:34:17 -0500825 * @brief Finds the inventory item associated with the specified led path.
826 * @param inventoryItems D-Bus inventory items associated with sensors.
827 * @param ledObjPath D-Bus object path of led.
828 * @return Inventory item within vector, or nullptr if no match found.
829 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400830inline InventoryItem* findInventoryItemForLed(
831 std::vector<InventoryItem>& inventoryItems, const std::string& ledObjPath)
Anthony Wilsond5005492019-07-31 16:34:17 -0500832{
833 for (InventoryItem& inventoryItem : inventoryItems)
834 {
835 if (inventoryItem.ledObjectPath == ledObjPath)
836 {
837 return &inventoryItem;
838 }
839 }
840 return nullptr;
841}
842
843/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500844 * @brief Adds inventory item and associated sensor to specified vector.
845 *
846 * Adds a new InventoryItem to the vector if necessary. Searches for an
847 * existing InventoryItem with the specified object path. If not found, one is
848 * added to the vector.
849 *
850 * Next, the specified sensor is added to the set of sensors associated with the
851 * InventoryItem.
852 *
853 * @param inventoryItems D-Bus inventory items associated with sensors.
854 * @param invItemObjPath D-Bus object path of inventory item.
855 * @param sensorObjPath D-Bus object path of sensor
856 */
Ed Tanousb5a76932020-09-29 16:16:58 -0700857inline void addInventoryItem(
858 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
859 const std::string& invItemObjPath, const std::string& sensorObjPath)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500860{
861 // Look for inventory item in vector
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400862 InventoryItem* inventoryItem =
863 findInventoryItem(inventoryItems, invItemObjPath);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500864
865 // If inventory item doesn't exist in vector, add it
866 if (inventoryItem == nullptr)
867 {
868 inventoryItems->emplace_back(invItemObjPath);
869 inventoryItem = &(inventoryItems->back());
870 }
871
872 // Add sensor to set of sensors associated with inventory item
873 inventoryItem->sensors.emplace(sensorObjPath);
874}
875
876/**
877 * @brief Stores D-Bus data in the specified inventory item.
878 *
879 * Finds D-Bus data in the specified map of interfaces. Stores the data in the
880 * specified InventoryItem.
881 *
882 * This data is later used to provide sensor property values in the JSON
883 * response.
884 *
885 * @param inventoryItem Inventory item where data will be stored.
886 * @param interfacesDict Map containing D-Bus interfaces and their properties
887 * for the specified inventory item.
888 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000889inline void storeInventoryItemData(
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500890 InventoryItem& inventoryItem,
Michael Shen80f79a42023-08-24 13:41:53 +0000891 const dbus::utility::DBusInterfacesMap& interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500892{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500893 // Get properties from Inventory.Item interface
Ed Tanous711ac7a2021-12-20 09:34:41 -0800894
Ed Tanous9eb808c2022-01-25 10:19:23 -0800895 for (const auto& [interface, values] : interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500896 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800897 if (interface == "xyz.openbmc_project.Inventory.Item")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500898 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800899 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500900 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800901 if (name == "Present")
902 {
903 const bool* value = std::get_if<bool>(&dbusValue);
904 if (value != nullptr)
905 {
906 inventoryItem.isPresent = *value;
907 }
908 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500909 }
910 }
Ed Tanous711ac7a2021-12-20 09:34:41 -0800911 // Check if Inventory.Item.PowerSupply interface is present
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500912
Ed Tanous711ac7a2021-12-20 09:34:41 -0800913 if (interface == "xyz.openbmc_project.Inventory.Item.PowerSupply")
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500914 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800915 inventoryItem.isPowerSupply = true;
916 }
917
918 // Get properties from Inventory.Decorator.Asset interface
919 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
920 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800921 for (const auto& [name, dbusValue] : values)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500922 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800923 if (name == "Manufacturer")
924 {
925 const std::string* value =
926 std::get_if<std::string>(&dbusValue);
927 if (value != nullptr)
928 {
929 inventoryItem.manufacturer = *value;
930 }
931 }
932 if (name == "Model")
933 {
934 const std::string* value =
935 std::get_if<std::string>(&dbusValue);
936 if (value != nullptr)
937 {
938 inventoryItem.model = *value;
939 }
940 }
941 if (name == "SerialNumber")
942 {
943 const std::string* value =
944 std::get_if<std::string>(&dbusValue);
945 if (value != nullptr)
946 {
947 inventoryItem.serialNumber = *value;
948 }
949 }
950 if (name == "PartNumber")
951 {
952 const std::string* value =
953 std::get_if<std::string>(&dbusValue);
954 if (value != nullptr)
955 {
956 inventoryItem.partNumber = *value;
957 }
958 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500959 }
960 }
961
Ed Tanous711ac7a2021-12-20 09:34:41 -0800962 if (interface ==
963 "xyz.openbmc_project.State.Decorator.OperationalStatus")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500964 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800965 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500966 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800967 if (name == "Functional")
968 {
969 const bool* value = std::get_if<bool>(&dbusValue);
970 if (value != nullptr)
971 {
972 inventoryItem.isFunctional = *value;
973 }
974 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500975 }
976 }
977 }
978}
979
980/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500981 * @brief Gets D-Bus data for inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500982 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500983 * Uses the specified connections (services) to obtain D-Bus data for inventory
984 * items associated with sensors. Stores the resulting data in the
985 * inventoryItems vector.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500986 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500987 * This data is later used to provide sensor property values in the JSON
988 * response.
989 *
990 * Finds the inventory item data asynchronously. Invokes callback when data has
991 * been obtained.
992 *
993 * The callback must have the following signature:
994 * @code
Anthony Wilsond5005492019-07-31 16:34:17 -0500995 * callback(void)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500996 * @endcode
997 *
998 * This function is called recursively, obtaining data asynchronously from one
999 * connection in each call. This ensures the callback is not invoked until the
1000 * last asynchronous function has completed.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001001 *
1002 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001003 * @param inventoryItems D-Bus inventory items associated with sensors.
1004 * @param invConnections Connections that provide data for the inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001005 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001006 * @param callback Callback to invoke when inventory data has been obtained.
1007 * @param invConnectionsIndex Current index in invConnections. Only specified
1008 * in recursive calls to this function.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001009 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001010template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001011void getInventoryItemsData(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001012 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1013 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
1014 const std::shared_ptr<std::set<std::string>>& invConnections,
1015 Callback&& callback, size_t invConnectionsIndex = 0)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001016{
Ed Tanous62598e32023-07-17 17:06:25 -07001017 BMCWEB_LOG_DEBUG("getInventoryItemsData enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001018
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001019 // If no more connections left, call callback
1020 if (invConnectionsIndex >= invConnections->size())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001021 {
Anthony Wilsond5005492019-07-31 16:34:17 -05001022 callback();
Ed Tanous62598e32023-07-17 17:06:25 -07001023 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001024 return;
1025 }
1026
1027 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +00001028 auto it = invConnections->begin();
1029 std::advance(it, invConnectionsIndex);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001030 if (it != invConnections->end())
1031 {
1032 const std::string& invConnection = *it;
1033
George Liu5eb468d2023-06-20 17:03:24 +08001034 // Get all object paths and their interfaces for current connection
1035 sdbusplus::message::object_path path("/xyz/openbmc_project/inventory");
1036 dbus::utility::getManagedObjects(
1037 invConnection, path,
1038 [sensorsAsyncResp, inventoryItems, invConnections,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001039 callback = std::forward<Callback>(callback), invConnectionsIndex](
George Liu5eb468d2023-06-20 17:03:24 +08001040 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001041 const dbus::utility::ManagedObjectType& resp) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001042 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler enter");
1043 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001044 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001045 BMCWEB_LOG_ERROR(
1046 "getInventoryItemsData respHandler DBus error {}", ec);
1047 messages::internalError(sensorsAsyncResp->asyncResp->res);
1048 return;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001049 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001050
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001051 // Loop through returned object paths
1052 for (const auto& objDictEntry : resp)
1053 {
1054 const std::string& objPath =
1055 static_cast<const std::string&>(objDictEntry.first);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001056
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001057 // If this object path is one of the specified inventory
1058 // items
1059 InventoryItem* inventoryItem =
1060 findInventoryItem(inventoryItems, objPath);
1061 if (inventoryItem != nullptr)
1062 {
1063 // Store inventory data in InventoryItem
1064 storeInventoryItemData(*inventoryItem,
1065 objDictEntry.second);
1066 }
1067 }
1068
1069 // Recurse to get inventory item data from next connection
1070 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1071 invConnections, std::move(callback),
1072 invConnectionsIndex + 1);
1073
1074 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler exit");
1075 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001076 }
1077
Ed Tanous62598e32023-07-17 17:06:25 -07001078 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001079}
1080
1081/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001082 * @brief Gets connections that provide D-Bus data for inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001083 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001084 * Gets the D-Bus connections (services) that provide data for the inventory
1085 * items that are associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001086 *
1087 * Finds the connections asynchronously. Invokes callback when information has
1088 * been obtained.
1089 *
1090 * The callback must have the following signature:
1091 * @code
Nan Zhoufe04d492022-06-22 17:10:41 +00001092 * callback(std::shared_ptr<std::set<std::string>> invConnections)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001093 * @endcode
1094 *
1095 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001096 * @param inventoryItems D-Bus inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001097 * @param callback Callback to invoke when connections have been obtained.
1098 */
1099template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001100void getInventoryItemsConnections(
Ed Tanousb5a76932020-09-29 16:16:58 -07001101 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1102 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001103 Callback&& callback)
1104{
Ed Tanous62598e32023-07-17 17:06:25 -07001105 BMCWEB_LOG_DEBUG("getInventoryItemsConnections enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001106
1107 const std::string path = "/xyz/openbmc_project/inventory";
George Liue99073f2022-12-09 11:06:16 +08001108 constexpr std::array<std::string_view, 4> interfaces = {
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001109 "xyz.openbmc_project.Inventory.Item",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001110 "xyz.openbmc_project.Inventory.Item.PowerSupply",
1111 "xyz.openbmc_project.Inventory.Decorator.Asset",
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001112 "xyz.openbmc_project.State.Decorator.OperationalStatus"};
1113
George Liue99073f2022-12-09 11:06:16 +08001114 // Make call to ObjectMapper to find all inventory items
1115 dbus::utility::getSubTree(
1116 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001117 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001118 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001119 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001120 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001121 // Response handler for parsing output from GetSubTree
1122 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler enter");
1123 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001124 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001125 messages::internalError(sensorsAsyncResp->asyncResp->res);
1126 BMCWEB_LOG_ERROR(
1127 "getInventoryItemsConnections respHandler DBus error {}",
1128 ec);
1129 return;
1130 }
1131
1132 // Make unique list of connections for desired inventory items
1133 std::shared_ptr<std::set<std::string>> invConnections =
1134 std::make_shared<std::set<std::string>>();
1135
1136 // Loop through objects from GetSubTree
1137 for (const std::pair<std::string,
1138 std::vector<std::pair<
1139 std::string, std::vector<std::string>>>>&
1140 object : subtree)
1141 {
1142 // Check if object path is one of the specified inventory items
1143 const std::string& objPath = object.first;
1144 if (findInventoryItem(inventoryItems, objPath) != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001145 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001146 // Store all connections to inventory item
1147 for (const std::pair<std::string, std::vector<std::string>>&
1148 objData : object.second)
1149 {
1150 const std::string& invConnection = objData.first;
1151 invConnections->insert(invConnection);
1152 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001153 }
1154 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001155
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001156 callback(invConnections);
1157 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler exit");
1158 });
Ed Tanous62598e32023-07-17 17:06:25 -07001159 BMCWEB_LOG_DEBUG("getInventoryItemsConnections exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001160}
1161
1162/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001163 * @brief Gets associations from sensors to inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001164 *
1165 * Looks for ObjectMapper associations from the specified sensors to related
Anthony Wilsond5005492019-07-31 16:34:17 -05001166 * inventory items. Then finds the associations from those inventory items to
1167 * their LEDs, if any.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001168 *
1169 * Finds the inventory items asynchronously. Invokes callback when information
1170 * has been obtained.
1171 *
1172 * The callback must have the following signature:
1173 * @code
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001174 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001175 * @endcode
1176 *
1177 * @param sensorsAsyncResp Pointer to object holding response data.
1178 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001179 * implements ObjectManager.
1180 * @param callback Callback to invoke when inventory items have been obtained.
1181 */
1182template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001183void getInventoryItemAssociations(
Ed Tanousb5a76932020-09-29 16:16:58 -07001184 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001185 const std::shared_ptr<std::set<std::string>>& sensorNames,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001186 Callback&& callback)
1187{
Ed Tanous62598e32023-07-17 17:06:25 -07001188 BMCWEB_LOG_DEBUG("getInventoryItemAssociations enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001189
George Liu5eb468d2023-06-20 17:03:24 +08001190 // Call GetManagedObjects on the ObjectMapper to get all associations
1191 sdbusplus::message::object_path path("/");
1192 dbus::utility::getManagedObjects(
1193 "xyz.openbmc_project.ObjectMapper", path,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001194 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001195 sensorNames](const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001196 const dbus::utility::ManagedObjectType& resp) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001197 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler enter");
1198 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001199 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001200 BMCWEB_LOG_ERROR(
1201 "getInventoryItemAssociations respHandler DBus error {}",
1202 ec);
1203 messages::internalError(sensorsAsyncResp->asyncResp->res);
1204 return;
1205 }
1206
1207 // Create vector to hold list of inventory items
1208 std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1209 std::make_shared<std::vector<InventoryItem>>();
1210
1211 // Loop through returned object paths
1212 std::string sensorAssocPath;
1213 sensorAssocPath.reserve(128); // avoid memory allocations
1214 for (const auto& objDictEntry : resp)
1215 {
1216 const std::string& objPath =
1217 static_cast<const std::string&>(objDictEntry.first);
1218
1219 // If path is inventory association for one of the specified
1220 // sensors
1221 for (const std::string& sensorName : *sensorNames)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001222 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001223 sensorAssocPath = sensorName;
1224 sensorAssocPath += "/inventory";
1225 if (objPath == sensorAssocPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001226 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001227 // Get Association interface for object path
1228 for (const auto& [interface, values] :
1229 objDictEntry.second)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001230 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001231 if (interface == "xyz.openbmc_project.Association")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001232 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001233 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001234 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001235 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001236 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001237 const std::vector<std::string>*
1238 endpoints = std::get_if<
1239 std::vector<std::string>>(
1240 &value);
1241 if ((endpoints != nullptr) &&
1242 !endpoints->empty())
1243 {
1244 // Add inventory item to vector
1245 const std::string& invItemPath =
1246 endpoints->front();
1247 addInventoryItem(inventoryItems,
1248 invItemPath,
1249 sensorName);
1250 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001251 }
1252 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001253 }
1254 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001255 break;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001256 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001257 }
1258 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001259
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001260 // Now loop through the returned object paths again, this time to
1261 // find the leds associated with the inventory items we just found
1262 std::string inventoryAssocPath;
1263 inventoryAssocPath.reserve(128); // avoid memory allocations
1264 for (const auto& objDictEntry : resp)
Anthony Wilsond5005492019-07-31 16:34:17 -05001265 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001266 const std::string& objPath =
1267 static_cast<const std::string&>(objDictEntry.first);
1268
1269 for (InventoryItem& inventoryItem : *inventoryItems)
Anthony Wilsond5005492019-07-31 16:34:17 -05001270 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001271 inventoryAssocPath = inventoryItem.objectPath;
1272 inventoryAssocPath += "/leds";
1273 if (objPath == inventoryAssocPath)
Anthony Wilsond5005492019-07-31 16:34:17 -05001274 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001275 for (const auto& [interface, values] :
1276 objDictEntry.second)
Anthony Wilsond5005492019-07-31 16:34:17 -05001277 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001278 if (interface == "xyz.openbmc_project.Association")
Anthony Wilsond5005492019-07-31 16:34:17 -05001279 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001280 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001281 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001282 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001283 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001284 const std::vector<std::string>*
1285 endpoints = std::get_if<
1286 std::vector<std::string>>(
1287 &value);
1288 if ((endpoints != nullptr) &&
1289 !endpoints->empty())
1290 {
1291 // Add inventory item to vector
1292 // Store LED path in inventory item
1293 const std::string& ledPath =
1294 endpoints->front();
1295 inventoryItem.ledObjectPath =
1296 ledPath;
1297 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001298 }
1299 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001300 }
1301 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001302
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001303 break;
1304 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001305 }
1306 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001307 callback(inventoryItems);
1308 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler exit");
1309 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001310
Ed Tanous62598e32023-07-17 17:06:25 -07001311 BMCWEB_LOG_DEBUG("getInventoryItemAssociations exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001312}
1313
1314/**
Anthony Wilsond5005492019-07-31 16:34:17 -05001315 * @brief Gets D-Bus data for inventory item leds associated with sensors.
1316 *
1317 * Uses the specified connections (services) to obtain D-Bus data for inventory
1318 * item leds associated with sensors. Stores the resulting data in the
1319 * inventoryItems vector.
1320 *
1321 * This data is later used to provide sensor property values in the JSON
1322 * response.
1323 *
1324 * Finds the inventory item led data asynchronously. Invokes callback when data
1325 * has been obtained.
1326 *
1327 * The callback must have the following signature:
1328 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001329 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001330 * @endcode
1331 *
1332 * This function is called recursively, obtaining data asynchronously from one
1333 * connection in each call. This ensures the callback is not invoked until the
1334 * last asynchronous function has completed.
1335 *
1336 * @param sensorsAsyncResp Pointer to object holding response data.
1337 * @param inventoryItems D-Bus inventory items associated with sensors.
1338 * @param ledConnections Connections that provide data for the inventory leds.
1339 * @param callback Callback to invoke when inventory data has been obtained.
1340 * @param ledConnectionsIndex Current index in ledConnections. Only specified
1341 * in recursive calls to this function.
1342 */
1343template <typename Callback>
1344void getInventoryLedData(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001345 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1346 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
1347 const std::shared_ptr<std::map<std::string, std::string>>& ledConnections,
Anthony Wilsond5005492019-07-31 16:34:17 -05001348 Callback&& callback, size_t ledConnectionsIndex = 0)
1349{
Ed Tanous62598e32023-07-17 17:06:25 -07001350 BMCWEB_LOG_DEBUG("getInventoryLedData enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001351
1352 // If no more connections left, call callback
1353 if (ledConnectionsIndex >= ledConnections->size())
1354 {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001355 callback();
Ed Tanous62598e32023-07-17 17:06:25 -07001356 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001357 return;
1358 }
1359
1360 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +00001361 auto it = ledConnections->begin();
1362 std::advance(it, ledConnectionsIndex);
Anthony Wilsond5005492019-07-31 16:34:17 -05001363 if (it != ledConnections->end())
1364 {
1365 const std::string& ledPath = (*it).first;
1366 const std::string& ledConnection = (*it).second;
1367 // Response handler for Get State property
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001368 auto respHandler =
1369 [sensorsAsyncResp, inventoryItems, ledConnections, ledPath,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001370 callback = std::forward<Callback>(callback),
1371 ledConnectionsIndex](const boost::system::error_code& ec,
1372 const std::string& state) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001373 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler enter");
1374 if (ec)
1375 {
1376 BMCWEB_LOG_ERROR(
1377 "getInventoryLedData respHandler DBus error {}", ec);
1378 messages::internalError(sensorsAsyncResp->asyncResp->res);
1379 return;
1380 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001381
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001382 BMCWEB_LOG_DEBUG("Led state: {}", state);
1383 // Find inventory item with this LED object path
1384 InventoryItem* inventoryItem =
1385 findInventoryItemForLed(*inventoryItems, ledPath);
1386 if (inventoryItem != nullptr)
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001387 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001388 // Store LED state in InventoryItem
1389 if (state.ends_with("On"))
1390 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001391 inventoryItem->ledState = sensor_utils::LedState::ON;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001392 }
1393 else if (state.ends_with("Blink"))
1394 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001395 inventoryItem->ledState = sensor_utils::LedState::BLINK;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001396 }
1397 else if (state.ends_with("Off"))
1398 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001399 inventoryItem->ledState = sensor_utils::LedState::OFF;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001400 }
1401 else
1402 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001403 inventoryItem->ledState =
1404 sensor_utils::LedState::UNKNOWN;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001405 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001406 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001407
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001408 // Recurse to get LED data from next connection
1409 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1410 ledConnections, std::move(callback),
1411 ledConnectionsIndex + 1);
Anthony Wilsond5005492019-07-31 16:34:17 -05001412
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001413 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler exit");
1414 };
Anthony Wilsond5005492019-07-31 16:34:17 -05001415
1416 // Get the State property for the current LED
Ed Tanousdeae6a72024-11-11 21:58:57 -08001417 dbus::utility::getProperty<std::string>(
1418 ledConnection, ledPath, "xyz.openbmc_project.Led.Physical", "State",
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001419 std::move(respHandler));
Anthony Wilsond5005492019-07-31 16:34:17 -05001420 }
1421
Ed Tanous62598e32023-07-17 17:06:25 -07001422 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001423}
1424
1425/**
1426 * @brief Gets LED data for LEDs associated with given inventory items.
1427 *
1428 * Gets the D-Bus connections (services) that provide LED data for the LEDs
1429 * associated with the specified inventory items. Then gets the LED data from
1430 * each connection and stores it in the inventory item.
1431 *
1432 * This data is later used to provide sensor property values in the JSON
1433 * response.
1434 *
1435 * Finds the LED data asynchronously. Invokes callback when information has
1436 * been obtained.
1437 *
1438 * The callback must have the following signature:
1439 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001440 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001441 * @endcode
1442 *
1443 * @param sensorsAsyncResp Pointer to object holding response data.
1444 * @param inventoryItems D-Bus inventory items associated with sensors.
1445 * @param callback Callback to invoke when inventory items have been obtained.
1446 */
1447template <typename Callback>
1448void getInventoryLeds(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001449 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1450 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Anthony Wilsond5005492019-07-31 16:34:17 -05001451 Callback&& callback)
1452{
Ed Tanous62598e32023-07-17 17:06:25 -07001453 BMCWEB_LOG_DEBUG("getInventoryLeds enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001454
1455 const std::string path = "/xyz/openbmc_project";
George Liue99073f2022-12-09 11:06:16 +08001456 constexpr std::array<std::string_view, 1> interfaces = {
Anthony Wilsond5005492019-07-31 16:34:17 -05001457 "xyz.openbmc_project.Led.Physical"};
1458
George Liue99073f2022-12-09 11:06:16 +08001459 // Make call to ObjectMapper to find all inventory items
1460 dbus::utility::getSubTree(
1461 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001462 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001463 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001464 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001465 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001466 // Response handler for parsing output from GetSubTree
1467 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler enter");
1468 if (ec)
Anthony Wilsond5005492019-07-31 16:34:17 -05001469 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001470 messages::internalError(sensorsAsyncResp->asyncResp->res);
1471 BMCWEB_LOG_ERROR("getInventoryLeds respHandler DBus error {}",
1472 ec);
1473 return;
Anthony Wilsond5005492019-07-31 16:34:17 -05001474 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001475
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001476 // Build map of LED object paths to connections
1477 std::shared_ptr<std::map<std::string, std::string>> ledConnections =
1478 std::make_shared<std::map<std::string, std::string>>();
1479
1480 // Loop through objects from GetSubTree
1481 for (const std::pair<std::string,
1482 std::vector<std::pair<
1483 std::string, std::vector<std::string>>>>&
1484 object : subtree)
1485 {
1486 // Check if object path is LED for one of the specified
1487 // inventory items
1488 const std::string& ledPath = object.first;
1489 if (findInventoryItemForLed(*inventoryItems, ledPath) !=
1490 nullptr)
1491 {
1492 // Add mapping from ledPath to connection
1493 const std::string& connection =
1494 object.second.begin()->first;
1495 (*ledConnections)[ledPath] = connection;
1496 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", ledPath,
1497 connection);
1498 }
1499 }
1500
1501 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1502 ledConnections, std::move(callback));
1503 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler exit");
1504 });
Ed Tanous62598e32023-07-17 17:06:25 -07001505 BMCWEB_LOG_DEBUG("getInventoryLeds exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001506}
1507
1508/**
Gunnar Mills42cbe532019-08-15 15:26:54 -05001509 * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent
1510 *
1511 * Uses the specified connections (services) (currently assumes just one) to
1512 * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in
1513 * the inventoryItems vector. Only stores data in Power Supply inventoryItems.
1514 *
1515 * This data is later used to provide sensor property values in the JSON
1516 * response.
1517 *
1518 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1519 * when data has been obtained.
1520 *
1521 * The callback must have the following signature:
1522 * @code
1523 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1524 * @endcode
1525 *
1526 * @param sensorsAsyncResp Pointer to object holding response data.
1527 * @param inventoryItems D-Bus inventory items associated with sensors.
1528 * @param psAttributesConnections Connections that provide data for the Power
1529 * Supply Attributes
1530 * @param callback Callback to invoke when data has been obtained.
1531 */
1532template <typename Callback>
1533void getPowerSupplyAttributesData(
Ed Tanousb5a76932020-09-29 16:16:58 -07001534 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Ed Tanousdaadfb22024-12-20 09:25:54 -08001535 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001536 const std::map<std::string, std::string>& psAttributesConnections,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001537 Callback&& callback)
1538{
Ed Tanous62598e32023-07-17 17:06:25 -07001539 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001540
1541 if (psAttributesConnections.empty())
1542 {
Ed Tanous62598e32023-07-17 17:06:25 -07001543 BMCWEB_LOG_DEBUG("Can't find PowerSupplyAttributes, no connections!");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001544 callback(inventoryItems);
1545 return;
1546 }
1547
1548 // Assuming just one connection (service) for now
Nan Zhoufe04d492022-06-22 17:10:41 +00001549 auto it = psAttributesConnections.begin();
Gunnar Mills42cbe532019-08-15 15:26:54 -05001550
1551 const std::string& psAttributesPath = (*it).first;
1552 const std::string& psAttributesConnection = (*it).second;
1553
1554 // Response handler for Get DeratingFactor property
Patrick Williams5a39f772023-10-20 11:20:21 -05001555 auto respHandler = [sensorsAsyncResp, inventoryItems,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001556 callback = std::forward<Callback>(callback)](
Patrick Williams5a39f772023-10-20 11:20:21 -05001557 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001558 uint32_t value) mutable {
Ed Tanous62598e32023-07-17 17:06:25 -07001559 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001560 if (ec)
1561 {
Ed Tanous62598e32023-07-17 17:06:25 -07001562 BMCWEB_LOG_ERROR(
1563 "getPowerSupplyAttributesData respHandler DBus error {}", ec);
zhanghch058d1b46d2021-04-01 11:18:24 +08001564 messages::internalError(sensorsAsyncResp->asyncResp->res);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001565 return;
1566 }
1567
Ed Tanous62598e32023-07-17 17:06:25 -07001568 BMCWEB_LOG_DEBUG("PS EfficiencyPercent value: {}", value);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001569 // Store value in Power Supply Inventory Items
1570 for (InventoryItem& inventoryItem : *inventoryItems)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001571 {
Ed Tanous55f79e62022-01-25 11:26:16 -08001572 if (inventoryItem.isPowerSupply)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001573 {
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001574 inventoryItem.powerSupplyEfficiencyPercent =
1575 static_cast<int>(value);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001576 }
1577 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001578
Ed Tanous62598e32023-07-17 17:06:25 -07001579 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001580 callback(inventoryItems);
1581 };
1582
1583 // Get the DeratingFactor property for the PowerSupplyAttributes
1584 // Currently only property on the interface/only one we care about
Ed Tanousdeae6a72024-11-11 21:58:57 -08001585 dbus::utility::getProperty<uint32_t>(
1586 psAttributesConnection, psAttributesPath,
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001587 "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
1588 std::move(respHandler));
Gunnar Mills42cbe532019-08-15 15:26:54 -05001589
Ed Tanous62598e32023-07-17 17:06:25 -07001590 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001591}
1592
1593/**
1594 * @brief Gets the Power Supply Attributes such as EfficiencyPercent
1595 *
1596 * Gets the D-Bus connection (service) that provides Power Supply Attributes
1597 * data. Then gets the Power Supply Attributes data from the connection
1598 * (currently just assumes 1 connection) and stores the data in the inventory
1599 * item.
1600 *
1601 * This data is later used to provide sensor property values in the JSON
1602 * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish.
1603 *
1604 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1605 * when information has been obtained.
1606 *
1607 * The callback must have the following signature:
1608 * @code
1609 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1610 * @endcode
1611 *
1612 * @param sensorsAsyncResp Pointer to object holding response data.
1613 * @param inventoryItems D-Bus inventory items associated with sensors.
1614 * @param callback Callback to invoke when data has been obtained.
1615 */
1616template <typename Callback>
1617void getPowerSupplyAttributes(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001618 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1619 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001620 Callback&& callback)
1621{
Ed Tanous62598e32023-07-17 17:06:25 -07001622 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001623
1624 // Only need the power supply attributes when the Power Schema
Janet Adkins0c728b42024-08-29 11:09:10 -05001625 if (sensorsAsyncResp->chassisSubNode != sensors::powerNodeStr)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001626 {
Ed Tanous62598e32023-07-17 17:06:25 -07001627 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit since not Power");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001628 callback(inventoryItems);
1629 return;
1630 }
1631
George Liue99073f2022-12-09 11:06:16 +08001632 constexpr std::array<std::string_view, 1> interfaces = {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001633 "xyz.openbmc_project.Control.PowerSupplyAttributes"};
1634
George Liue99073f2022-12-09 11:06:16 +08001635 // Make call to ObjectMapper to find the PowerSupplyAttributes service
1636 dbus::utility::getSubTree(
1637 "/xyz/openbmc_project", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001638 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001639 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001640 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001641 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001642 // Response handler for parsing output from GetSubTree
1643 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler enter");
1644 if (ec)
1645 {
1646 messages::internalError(sensorsAsyncResp->asyncResp->res);
1647 BMCWEB_LOG_ERROR(
1648 "getPowerSupplyAttributes respHandler DBus error {}", ec);
1649 return;
1650 }
1651 if (subtree.empty())
1652 {
1653 BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
1654 callback(inventoryItems);
1655 return;
1656 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001657
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001658 // Currently we only support 1 power supply attribute, use this for
1659 // all the power supplies. Build map of object path to connection.
1660 // Assume just 1 connection and 1 path for now.
1661 std::map<std::string, std::string> psAttributesConnections;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001662
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001663 if (subtree[0].first.empty() || subtree[0].second.empty())
1664 {
1665 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1666 callback(inventoryItems);
1667 return;
1668 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001669
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001670 const std::string& psAttributesPath = subtree[0].first;
1671 const std::string& connection = subtree[0].second.begin()->first;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001672
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001673 if (connection.empty())
1674 {
1675 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1676 callback(inventoryItems);
1677 return;
1678 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001679
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001680 psAttributesConnections[psAttributesPath] = connection;
1681 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", psAttributesPath,
1682 connection);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001683
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001684 getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems,
1685 psAttributesConnections,
1686 std::move(callback));
1687 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler exit");
1688 });
Ed Tanous62598e32023-07-17 17:06:25 -07001689 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001690}
1691
1692/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001693 * @brief Gets inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001694 *
1695 * Finds the inventory items that are associated with the specified sensors.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001696 * Then gets D-Bus data for the inventory items, such as presence and VPD.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001697 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001698 * This data is later used to provide sensor property values in the JSON
1699 * response.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001700 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001701 * Finds the inventory items asynchronously. Invokes callback when the
1702 * inventory items have been obtained.
1703 *
1704 * The callback must have the following signature:
1705 * @code
1706 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1707 * @endcode
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001708 *
1709 * @param sensorsAsyncResp Pointer to object holding response data.
1710 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001711 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001712 * @param callback Callback to invoke when inventory items have been obtained.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001713 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001714template <typename Callback>
Patrick Williams504af5a2025-02-03 14:29:03 -05001715inline void getInventoryItems(
1716 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1717 const std::shared_ptr<std::set<std::string>>& sensorNames,
1718 Callback&& callback)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001719{
Ed Tanous62598e32023-07-17 17:06:25 -07001720 BMCWEB_LOG_DEBUG("getInventoryItems enter");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001721 auto getInventoryItemAssociationsCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -07001722 [sensorsAsyncResp, callback = std::forward<Callback>(callback)](
Ed Tanousdaadfb22024-12-20 09:25:54 -08001723 const std::shared_ptr<std::vector<InventoryItem>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07001724 inventoryItems) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001725 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb enter");
1726 auto getInventoryItemsConnectionsCb =
1727 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001728 callback = std::forward<Callback>(callback)](
Ed Tanousdaadfb22024-12-20 09:25:54 -08001729 const std::shared_ptr<std::set<std::string>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07001730 invConnections) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001731 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb enter");
1732 auto getInventoryItemsDataCb =
1733 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001734 callback =
1735 std::forward<Callback>(callback)]() mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001736 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001737
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001738 auto getInventoryLedsCb =
1739 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001740 callback = std::forward<Callback>(
1741 callback)]() mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001742 BMCWEB_LOG_DEBUG(
1743 "getInventoryLedsCb enter");
1744 // Find Power Supply Attributes and get the
1745 // data
1746 getPowerSupplyAttributes(
1747 sensorsAsyncResp, inventoryItems,
1748 std::move(callback));
1749 BMCWEB_LOG_DEBUG("getInventoryLedsCb exit");
1750 };
1751
1752 // Find led connections and get the data
1753 getInventoryLeds(sensorsAsyncResp, inventoryItems,
1754 std::move(getInventoryLedsCb));
1755 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb exit");
1756 };
1757
1758 // Get inventory item data from connections
1759 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1760 invConnections,
1761 std::move(getInventoryItemsDataCb));
1762 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001763 };
1764
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001765 // Get connections that provide inventory item data
1766 getInventoryItemsConnections(
1767 sensorsAsyncResp, inventoryItems,
1768 std::move(getInventoryItemsConnectionsCb));
1769 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001770 };
1771
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001772 // Get associations from sensors to inventory items
Ed Tanousd0090732022-10-04 17:22:56 -07001773 getInventoryItemAssociations(sensorsAsyncResp, sensorNames,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001774 std::move(getInventoryItemAssociationsCb));
Ed Tanous62598e32023-07-17 17:06:25 -07001775 BMCWEB_LOG_DEBUG("getInventoryItems exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001776}
1777
1778/**
1779 * @brief Returns JSON PowerSupply object for the specified inventory item.
1780 *
1781 * Searches for a JSON PowerSupply object that matches the specified inventory
1782 * item. If one is not found, a new PowerSupply object is added to the JSON
1783 * array.
1784 *
1785 * Multiple sensors are often associated with one power supply inventory item.
1786 * As a result, multiple sensor values are stored in one JSON PowerSupply
1787 * object.
1788 *
1789 * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1790 * @param inventoryItem Inventory item for the power supply.
1791 * @param chassisId Chassis that contains the power supply.
1792 * @return JSON PowerSupply object for the specified inventory item.
1793 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001794inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001795 const InventoryItem& inventoryItem,
1796 const std::string& chassisId)
1797{
Ed Tanous18f8f602023-07-18 10:07:23 -07001798 std::string nameS;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001799 nameS.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001800 std::ranges::replace_copy(inventoryItem.name, nameS.begin(), '_', ' ');
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001801 // Check if matching PowerSupply object already exists in JSON array
1802 for (nlohmann::json& powerSupply : powerSupplyArray)
1803 {
Ed Tanous18f8f602023-07-18 10:07:23 -07001804 nlohmann::json::iterator nameIt = powerSupply.find("Name");
1805 if (nameIt == powerSupply.end())
1806 {
1807 continue;
1808 }
1809 const std::string* name = nameIt->get_ptr<std::string*>();
1810 if (name == nullptr)
1811 {
1812 continue;
1813 }
1814 if (nameS == *name)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001815 {
1816 return powerSupply;
1817 }
1818 }
1819
1820 // Add new PowerSupply object to JSON array
1821 powerSupplyArray.push_back({});
1822 nlohmann::json& powerSupply = powerSupplyArray.back();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001823 boost::urls::url url =
1824 boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
Willy Tueddfc432022-09-26 16:46:38 +00001825 url.set_fragment(("/PowerSupplies"_json_pointer).to_string());
1826 powerSupply["@odata.id"] = std::move(url);
Ed Tanous18f8f602023-07-18 10:07:23 -07001827 std::string escaped;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001828 escaped.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001829 std::ranges::replace_copy(inventoryItem.name, escaped.begin(), '_', ' ');
1830 powerSupply["Name"] = std::move(escaped);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001831 powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1832 powerSupply["Model"] = inventoryItem.model;
1833 powerSupply["PartNumber"] = inventoryItem.partNumber;
1834 powerSupply["SerialNumber"] = inventoryItem.serialNumber;
Janet Adkinsc9563602024-08-28 11:37:46 -05001835 sensor_utils::setLedState(powerSupply, &inventoryItem);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001836
Gunnar Mills42cbe532019-08-15 15:26:54 -05001837 if (inventoryItem.powerSupplyEfficiencyPercent >= 0)
1838 {
1839 powerSupply["EfficiencyPercent"] =
1840 inventoryItem.powerSupplyEfficiencyPercent;
1841 }
1842
Janet Adkinsc9563602024-08-28 11:37:46 -05001843 powerSupply["Status"]["State"] =
1844 sensor_utils::getState(&inventoryItem, true);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001845 const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1846 powerSupply["Status"]["Health"] = health;
1847
1848 return powerSupply;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001849}
1850
1851/**
Shawn McCarneyde629b62019-03-08 10:42:51 -06001852 * @brief Gets the values of the specified sensors.
1853 *
1854 * Stores the results as JSON in the SensorsAsyncResp.
1855 *
1856 * Gets the sensor values asynchronously. Stores the results later when the
1857 * information has been obtained.
1858 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001859 * The sensorNames set contains all requested sensors for the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001860 *
1861 * To minimize the number of DBus calls, the DBus method
1862 * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1863 * values of all sensors provided by a connection (service).
1864 *
1865 * The connections set contains all the connections that provide sensor values.
1866 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001867 * The InventoryItem vector contains D-Bus inventory items associated with the
1868 * sensors. Inventory item data is needed for some Redfish sensor properties.
1869 *
Shawn McCarneyde629b62019-03-08 10:42:51 -06001870 * @param SensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001871 * @param sensorNames All requested sensors within the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001872 * @param connections Connections that provide sensor values.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001873 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001874 * @param inventoryItems Inventory items associated with the sensors.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001875 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001876inline void getSensorData(
Ed Tanous81ce6092020-12-17 16:54:55 +00001877 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001878 const std::shared_ptr<std::set<std::string>>& sensorNames,
1879 const std::set<std::string>& connections,
Ed Tanousb5a76932020-09-29 16:16:58 -07001880 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001881{
Ed Tanous62598e32023-07-17 17:06:25 -07001882 BMCWEB_LOG_DEBUG("getSensorData enter");
Shawn McCarneyde629b62019-03-08 10:42:51 -06001883 // Get managed objects from all services exposing sensors
1884 for (const std::string& connection : connections)
1885 {
George Liu5eb468d2023-06-20 17:03:24 +08001886 sdbusplus::message::object_path sensorPath(
1887 "/xyz/openbmc_project/sensors");
1888 dbus::utility::getManagedObjects(
1889 connection, sensorPath,
Ed Tanous002d39b2022-05-31 08:59:27 -07001890 [sensorsAsyncResp, sensorNames,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001891 inventoryItems](const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -07001892 const dbus::utility::ManagedObjectType& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001893 BMCWEB_LOG_DEBUG("getManagedObjectsCb enter");
1894 if (ec)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001895 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001896 BMCWEB_LOG_ERROR("getManagedObjectsCb DBUS error: {}", ec);
1897 messages::internalError(sensorsAsyncResp->asyncResp->res);
1898 return;
1899 }
Janet Adkins0c728b42024-08-29 11:09:10 -05001900 auto chassisSubNode = sensor_utils::chassisSubNodeFromString(
1901 sensorsAsyncResp->chassisSubNode);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001902 // Go through all objects and update response with sensor data
1903 for (const auto& objDictEntry : resp)
1904 {
1905 const std::string& objPath =
1906 static_cast<const std::string&>(objDictEntry.first);
1907 BMCWEB_LOG_DEBUG("getManagedObjectsCb parsing object {}",
Ed Tanous62598e32023-07-17 17:06:25 -07001908 objPath);
Shawn McCarneyde629b62019-03-08 10:42:51 -06001909
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001910 std::vector<std::string> split;
1911 // Reserve space for
1912 // /xyz/openbmc_project/sensors/<name>/<subname>
1913 split.reserve(6);
1914 // NOLINTNEXTLINE
1915 bmcweb::split(split, objPath, '/');
1916 if (split.size() < 6)
Nan Zhou928fefb2022-03-28 08:45:00 -07001917 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001918 BMCWEB_LOG_ERROR("Got path that isn't long enough {}",
1919 objPath);
1920 continue;
Nan Zhou928fefb2022-03-28 08:45:00 -07001921 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001922 // These indexes aren't intuitive, as split puts an empty
1923 // string at the beginning
1924 const std::string& sensorType = split[4];
1925 const std::string& sensorName = split[5];
1926 BMCWEB_LOG_DEBUG("sensorName {} sensorType {}", sensorName,
1927 sensorType);
Ed Tanous3d158642025-05-12 14:20:49 -07001928 if (!sensorNames->contains(objPath))
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001929 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001930 BMCWEB_LOG_DEBUG("{} not in sensor list ", sensorName);
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001931 continue;
1932 }
1933
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001934 // Find inventory item (if any) associated with sensor
1935 InventoryItem* inventoryItem =
1936 findInventoryItemForSensor(inventoryItems, objPath);
1937
1938 const std::string& sensorSchema =
1939 sensorsAsyncResp->chassisSubNode;
1940
1941 nlohmann::json* sensorJson = nullptr;
1942
Janet Adkins0c728b42024-08-29 11:09:10 -05001943 if (sensorSchema == sensors::sensorsNodeStr &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001944 !sensorsAsyncResp->efficientExpand)
Nan Zhou928fefb2022-03-28 08:45:00 -07001945 {
Janet Adkins1516c212024-08-14 13:22:41 -05001946 std::string sensorId =
1947 redfish::sensor_utils::getSensorId(sensorName,
1948 sensorType);
Ed Tanous677bb752022-09-15 10:52:19 -07001949
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001950 sensorsAsyncResp->asyncResp->res
1951 .jsonValue["@odata.id"] = boost::urls::format(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001952 "/redfish/v1/Chassis/{}/{}/{}",
Ed Tanous677bb752022-09-15 10:52:19 -07001953 sensorsAsyncResp->chassisId,
1954 sensorsAsyncResp->chassisSubNode, sensorId);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001955 sensorJson =
1956 &(sensorsAsyncResp->asyncResp->res.jsonValue);
Nan Zhou928fefb2022-03-28 08:45:00 -07001957 }
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001958 else
1959 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001960 std::string fieldName;
1961 if (sensorsAsyncResp->efficientExpand)
1962 {
1963 fieldName = "Members";
1964 }
1965 else if (sensorType == "temperature")
1966 {
1967 fieldName = "Temperatures";
1968 }
1969 else if (sensorType == "fan" ||
1970 sensorType == "fan_tach" ||
1971 sensorType == "fan_pwm")
1972 {
1973 fieldName = "Fans";
1974 }
1975 else if (sensorType == "voltage")
1976 {
1977 fieldName = "Voltages";
1978 }
1979 else if (sensorType == "power")
1980 {
1981 if (sensorName == "total_power")
1982 {
1983 fieldName = "PowerControl";
1984 }
1985 else if ((inventoryItem != nullptr) &&
1986 (inventoryItem->isPowerSupply))
1987 {
1988 fieldName = "PowerSupplies";
1989 }
1990 else
1991 {
1992 // Other power sensors are in SensorCollection
1993 continue;
1994 }
1995 }
1996 else
1997 {
1998 BMCWEB_LOG_ERROR(
1999 "Unsure how to handle sensorType {}",
2000 sensorType);
2001 continue;
2002 }
2003
2004 nlohmann::json& tempArray =
2005 sensorsAsyncResp->asyncResp->res
2006 .jsonValue[fieldName];
2007 if (fieldName == "PowerControl")
2008 {
2009 if (tempArray.empty())
2010 {
2011 // Put multiple "sensors" into a single
2012 // PowerControl. Follows MemberId naming and
2013 // naming in power.hpp.
2014 nlohmann::json::object_t power;
2015 boost::urls::url url = boost::urls::format(
2016 "/redfish/v1/Chassis/{}/{}",
2017 sensorsAsyncResp->chassisId,
2018 sensorsAsyncResp->chassisSubNode);
2019 url.set_fragment(
2020 (""_json_pointer / fieldName / "0")
2021 .to_string());
2022 power["@odata.id"] = std::move(url);
2023 tempArray.emplace_back(std::move(power));
2024 }
2025 sensorJson = &(tempArray.back());
2026 }
2027 else if (fieldName == "PowerSupplies")
2028 {
2029 if (inventoryItem != nullptr)
2030 {
2031 sensorJson = &(getPowerSupply(
2032 tempArray, *inventoryItem,
2033 sensorsAsyncResp->chassisId));
2034 }
2035 }
2036 else if (fieldName == "Members")
2037 {
Janet Adkins1516c212024-08-14 13:22:41 -05002038 std::string sensorId =
2039 redfish::sensor_utils::getSensorId(sensorName,
2040 sensorType);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002041
2042 nlohmann::json::object_t member;
2043 member["@odata.id"] = boost::urls::format(
2044 "/redfish/v1/Chassis/{}/{}/{}",
2045 sensorsAsyncResp->chassisId,
2046 sensorsAsyncResp->chassisSubNode, sensorId);
2047 tempArray.emplace_back(std::move(member));
2048 sensorJson = &(tempArray.back());
2049 }
2050 else
2051 {
2052 nlohmann::json::object_t member;
2053 boost::urls::url url = boost::urls::format(
2054 "/redfish/v1/Chassis/{}/{}",
2055 sensorsAsyncResp->chassisId,
2056 sensorsAsyncResp->chassisSubNode);
2057 url.set_fragment(
2058 (""_json_pointer / fieldName).to_string());
2059 member["@odata.id"] = std::move(url);
2060 tempArray.emplace_back(std::move(member));
2061 sensorJson = &(tempArray.back());
2062 }
2063 }
2064
2065 if (sensorJson != nullptr)
2066 {
Janet Adkins0c728b42024-08-29 11:09:10 -05002067 objectInterfacesToJson(
2068 sensorName, sensorType, chassisSubNode,
2069 objDictEntry.second, *sensorJson, inventoryItem);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002070
2071 std::string path = "/xyz/openbmc_project/sensors/";
2072 path += sensorType;
2073 path += "/";
2074 path += sensorName;
2075 sensorsAsyncResp->addMetadata(*sensorJson, path);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002076 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002077 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002078 if (sensorsAsyncResp.use_count() == 1)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002079 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002080 sortJSONResponse(sensorsAsyncResp);
Janet Adkins0c728b42024-08-29 11:09:10 -05002081 if (chassisSubNode ==
2082 sensor_utils::ChassisSubNode::sensorsNode &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002083 sensorsAsyncResp->efficientExpand)
2084 {
2085 sensorsAsyncResp->asyncResp->res
2086 .jsonValue["Members@odata.count"] =
2087 sensorsAsyncResp->asyncResp->res
2088 .jsonValue["Members"]
2089 .size();
2090 }
Janet Adkins0c728b42024-08-29 11:09:10 -05002091 else if (chassisSubNode ==
2092 sensor_utils::ChassisSubNode::thermalNode)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002093 {
2094 populateFanRedundancy(sensorsAsyncResp);
2095 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002096 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002097 BMCWEB_LOG_DEBUG("getManagedObjectsCb exit");
2098 });
Ed Tanous23a21a12020-07-25 04:45:05 +00002099 }
Ed Tanous62598e32023-07-17 17:06:25 -07002100 BMCWEB_LOG_DEBUG("getSensorData exit");
Shawn McCarneyde629b62019-03-08 10:42:51 -06002101}
2102
Patrick Williams504af5a2025-02-03 14:29:03 -05002103inline void processSensorList(
2104 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
2105 const std::shared_ptr<std::set<std::string>>& sensorNames)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002106{
Nan Zhoufe04d492022-06-22 17:10:41 +00002107 auto getConnectionCb = [sensorsAsyncResp, sensorNames](
2108 const std::set<std::string>& connections) {
Ed Tanous62598e32023-07-17 17:06:25 -07002109 BMCWEB_LOG_DEBUG("getConnectionCb enter");
Ed Tanousd0090732022-10-04 17:22:56 -07002110 auto getInventoryItemsCb =
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002111 [sensorsAsyncResp, sensorNames, connections](
2112 const std::shared_ptr<std::vector<InventoryItem>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07002113 inventoryItems) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002114 BMCWEB_LOG_DEBUG("getInventoryItemsCb enter");
2115 // Get sensor data and store results in JSON
2116 getSensorData(sensorsAsyncResp, sensorNames, connections,
2117 inventoryItems);
2118 BMCWEB_LOG_DEBUG("getInventoryItemsCb exit");
2119 };
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002120
Ed Tanousd0090732022-10-04 17:22:56 -07002121 // Get inventory items associated with sensors
2122 getInventoryItems(sensorsAsyncResp, sensorNames,
2123 std::move(getInventoryItemsCb));
2124
Ed Tanous62598e32023-07-17 17:06:25 -07002125 BMCWEB_LOG_DEBUG("getConnectionCb exit");
Ed Tanous002d39b2022-05-31 08:59:27 -07002126 };
2127
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002128 // Get set of connections that provide sensor values
Ed Tanous81ce6092020-12-17 16:54:55 +00002129 getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002130}
2131
Shawn McCarneyde629b62019-03-08 10:42:51 -06002132/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002133 * @brief Entry point for retrieving sensors data related to requested
2134 * chassis.
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02002135 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002136 */
Patrick Williams504af5a2025-02-03 14:29:03 -05002137inline void getChassisData(
2138 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002139{
Ed Tanous62598e32023-07-17 17:06:25 -07002140 BMCWEB_LOG_DEBUG("getChassisData enter");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002141 auto getChassisCb =
Ed Tanous81ce6092020-12-17 16:54:55 +00002142 [sensorsAsyncResp](
Nan Zhoufe04d492022-06-22 17:10:41 +00002143 const std::shared_ptr<std::set<std::string>>& sensorNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002144 BMCWEB_LOG_DEBUG("getChassisCb enter");
2145 processSensorList(sensorsAsyncResp, sensorNames);
2146 BMCWEB_LOG_DEBUG("getChassisCb exit");
2147 };
Nan Zhou928fefb2022-03-28 08:45:00 -07002148 // SensorCollection doesn't contain the Redundancy property
Janet Adkins0c728b42024-08-29 11:09:10 -05002149 if (sensorsAsyncResp->chassisSubNode != sensors::sensorsNodeStr)
Nan Zhou928fefb2022-03-28 08:45:00 -07002150 {
2151 sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
2152 nlohmann::json::array();
2153 }
Shawn McCarney26f03892019-05-03 13:20:24 -05002154 // Get set of sensors in chassis
Ed Tanous7f1cc262022-08-09 13:33:57 -07002155 getChassis(sensorsAsyncResp->asyncResp, sensorsAsyncResp->chassisId,
2156 sensorsAsyncResp->chassisSubNode, sensorsAsyncResp->types,
2157 std::move(getChassisCb));
Ed Tanous62598e32023-07-17 17:06:25 -07002158 BMCWEB_LOG_DEBUG("getChassisData exit");
Ed Tanous271584a2019-07-09 16:24:22 -07002159}
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002160
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302161/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002162 * @brief Find the requested sensorName in the list of all sensors supplied by
2163 * the chassis node
2164 *
2165 * @param sensorName The sensor name supplied in the PATCH request
2166 * @param sensorsList The list of sensors managed by the chassis node
2167 * @param sensorsModified The list of sensors that were found as a result of
2168 * repeated calls to this function
2169 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002170inline bool findSensorNameUsingSensorPath(
2171 std::string_view sensorName, const std::set<std::string>& sensorsList,
2172 std::set<std::string>& sensorsModified)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002173{
Nan Zhoufe04d492022-06-22 17:10:41 +00002174 for (const auto& chassisSensor : sensorsList)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002175 {
George Liu28aa8de2021-02-01 15:13:30 +08002176 sdbusplus::message::object_path path(chassisSensor);
Ed Tanousb00dcc22021-02-23 12:52:50 -08002177 std::string thisSensorName = path.filename();
George Liu28aa8de2021-02-01 15:13:30 +08002178 if (thisSensorName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002179 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002180 continue;
2181 }
2182 if (thisSensorName == sensorName)
2183 {
2184 sensorsModified.emplace(chassisSensor);
2185 return true;
2186 }
2187 }
2188 return false;
2189}
2190
2191/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302192 * @brief Entry point for overriding sensor values of given sensor
2193 *
zhanghch058d1b46d2021-04-01 11:18:24 +08002194 * @param sensorAsyncResp response object
Carol Wang4bb3dc32019-10-17 18:15:02 +08002195 * @param allCollections Collections extract from sensors' request patch info
jayaprakash Mutyala91e130a2020-03-04 22:26:38 +00002196 * @param chassisSubNode Chassis Node for which the query has to happen
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302197 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002198inline void setSensorsOverride(
Ed Tanousb5a76932020-09-29 16:16:58 -07002199 const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
Ed Tanous08850572024-03-06 15:09:17 -08002200 std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>&
jayaprakash Mutyala397fd612020-02-06 23:33:34 +00002201 allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302202{
Ed Tanous62598e32023-07-17 17:06:25 -07002203 BMCWEB_LOG_INFO("setSensorsOverride for subNode{}",
2204 sensorAsyncResp->chassisSubNode);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302205
Ed Tanousd02aad32024-02-13 14:43:34 -08002206 std::string_view propertyValueName;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302207 std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302208 std::string memberId;
Ed Tanous543f4402022-01-06 13:12:53 -08002209 double value = 0.0;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302210 for (auto& collectionItems : allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302211 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302212 if (collectionItems.first == "Temperatures")
2213 {
2214 propertyValueName = "ReadingCelsius";
2215 }
2216 else if (collectionItems.first == "Fans")
2217 {
2218 propertyValueName = "Reading";
2219 }
2220 else
2221 {
2222 propertyValueName = "ReadingVolts";
2223 }
2224 for (auto& item : collectionItems.second)
2225 {
Patrick Williams504af5a2025-02-03 14:29:03 -05002226 if (!json_util::readJsonObject( //
Myung Baeafc474a2024-10-09 00:53:29 -07002227 item, sensorAsyncResp->asyncResp->res, //
Patrick Williams504af5a2025-02-03 14:29:03 -05002228 "MemberId", memberId, //
2229 propertyValueName, value //
Myung Baeafc474a2024-10-09 00:53:29 -07002230 ))
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302231 {
2232 return;
2233 }
2234 overrideMap.emplace(memberId,
2235 std::make_pair(value, collectionItems.first));
2236 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302237 }
Carol Wang4bb3dc32019-10-17 18:15:02 +08002238
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002239 auto getChassisSensorListCb = [sensorAsyncResp, overrideMap,
2240 propertyValueNameStr =
2241 std::string(propertyValueName)](
2242 const std::shared_ptr<
2243 std::set<std::string>>& sensorsList) {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002244 // Match sensor names in the PATCH request to those managed by the
2245 // chassis node
Nan Zhoufe04d492022-06-22 17:10:41 +00002246 const std::shared_ptr<std::set<std::string>> sensorNames =
2247 std::make_shared<std::set<std::string>>();
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302248 for (const auto& item : overrideMap)
2249 {
2250 const auto& sensor = item.first;
Ed Tanousc71d6122022-11-29 14:10:32 -08002251 std::pair<std::string, std::string> sensorNameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002252 redfish::sensor_utils::splitSensorNameAndType(sensor);
Ed Tanousc71d6122022-11-29 14:10:32 -08002253 if (!findSensorNameUsingSensorPath(sensorNameType.second,
2254 *sensorsList, *sensorNames))
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302255 {
Ed Tanous62598e32023-07-17 17:06:25 -07002256 BMCWEB_LOG_INFO("Unable to find memberId {}", item.first);
zhanghch058d1b46d2021-04-01 11:18:24 +08002257 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302258 item.second.second, item.first);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302259 return;
2260 }
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302261 }
2262 // Get the connection to which the memberId belongs
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002263 auto getObjectsWithConnectionCb = [sensorAsyncResp, overrideMap,
2264 propertyValueNameStr](
2265 const std::set<
2266 std::string>& /*connections*/,
2267 const std::set<std::pair<
2268 std::string, std::string>>&
2269 objectsWithConnection) {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002270 if (objectsWithConnection.size() != overrideMap.size())
2271 {
Ed Tanous62598e32023-07-17 17:06:25 -07002272 BMCWEB_LOG_INFO(
2273 "Unable to find all objects with proper connection {} requested {}",
2274 objectsWithConnection.size(), overrideMap.size());
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002275 messages::resourceNotFound(
2276 sensorAsyncResp->asyncResp->res,
Janet Adkins0c728b42024-08-29 11:09:10 -05002277 sensorAsyncResp->chassisSubNode == sensors::thermalNodeStr
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002278 ? "Temperatures"
2279 : "Voltages",
2280 "Count");
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002281 return;
2282 }
2283 for (const auto& item : objectsWithConnection)
2284 {
2285 sdbusplus::message::object_path path(item.first);
2286 std::string sensorName = path.filename();
2287 if (sensorName.empty())
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302288 {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002289 messages::internalError(sensorAsyncResp->asyncResp->res);
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302290 return;
2291 }
Janet Adkins1516c212024-08-14 13:22:41 -05002292 std::string id = redfish::sensor_utils::getSensorId(
2293 sensorName, path.parent_path().filename());
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302294
Ban Feng3f5eb752023-06-29 09:19:20 +08002295 const auto& iterator = overrideMap.find(id);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002296 if (iterator == overrideMap.end())
2297 {
Ed Tanous62598e32023-07-17 17:06:25 -07002298 BMCWEB_LOG_INFO("Unable to find sensor object{}",
2299 item.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002300 messages::internalError(sensorAsyncResp->asyncResp->res);
2301 return;
2302 }
Ginu Georgee93abac2024-06-14 17:35:27 +05302303 setDbusProperty(sensorAsyncResp->asyncResp,
2304 propertyValueNameStr, item.second, item.first,
2305 "xyz.openbmc_project.Sensor.Value", "Value",
Ed Tanousd02aad32024-02-13 14:43:34 -08002306 iterator->second.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002307 }
2308 };
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302309 // Get object with connection for the given sensor name
2310 getObjectsWithConnection(sensorAsyncResp, sensorNames,
2311 std::move(getObjectsWithConnectionCb));
2312 };
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302313 // get full sensor list for the given chassisId and cross verify the sensor.
Ed Tanous7f1cc262022-08-09 13:33:57 -07002314 getChassis(sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId,
2315 sensorAsyncResp->chassisSubNode, sensorAsyncResp->types,
2316 std::move(getChassisSensorListCb));
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302317}
2318
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002319/**
2320 * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus
2321 * path of the sensor.
2322 *
2323 * Function builds valid Redfish response for sensor query of given chassis and
2324 * node. It then builds metadata about Redfish<->D-Bus correlations and provides
2325 * it to caller in a callback.
2326 *
2327 * @param chassis Chassis for which retrieval should be performed
Janet Adkinsc9563602024-08-28 11:37:46 -05002328 * @param node Node (group) of sensors. See sensor_utils::node for supported
2329 * values
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002330 * @param mapComplete Callback to be called with retrieval result
2331 */
Ed Tanous931edc72023-11-01 12:09:07 -07002332template <typename Callback>
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002333inline void retrieveUriToDbusMap(
2334 const std::string& chassis, const std::string& node, Callback&& mapComplete)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002335{
Ed Tanous02da7c52022-02-27 00:09:02 -08002336 decltype(sensors::paths)::const_iterator pathIt =
2337 std::find_if(sensors::paths.cbegin(), sensors::paths.cend(),
2338 [&node](auto&& val) { return val.first == node; });
2339 if (pathIt == sensors::paths.cend())
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002340 {
Ed Tanous62598e32023-07-17 17:06:25 -07002341 BMCWEB_LOG_ERROR("Wrong node provided : {}", node);
Ed Tanous6804b5c2023-10-31 14:50:03 -07002342 std::map<std::string, std::string> noop;
2343 mapComplete(boost::beast::http::status::bad_request, noop);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002344 return;
2345 }
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002346
Nan Zhou72374eb2022-01-27 17:06:51 -08002347 auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002348 auto callback =
2349 [asyncResp, mapCompleteCb = std::forward<Callback>(mapComplete)](
2350 const boost::beast::http::status status,
2351 const std::map<std::string, std::string>& uriToDbus) {
2352 mapCompleteCb(status, uriToDbus);
2353 };
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002354
2355 auto resp = std::make_shared<SensorsAsyncResp>(
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002356 asyncResp, chassis, pathIt->second, node, std::move(callback));
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002357 getChassisData(resp);
2358}
2359
Nan Zhoubacb2162022-04-06 11:28:32 -07002360namespace sensors
2361{
Nan Zhou928fefb2022-03-28 08:45:00 -07002362
Nan Zhoubacb2162022-04-06 11:28:32 -07002363inline void getChassisCallback(
Ed Tanousc1d019a2022-08-06 09:36:06 -07002364 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2365 std::string_view chassisId, std::string_view chassisSubNode,
Nan Zhoufe04d492022-06-22 17:10:41 +00002366 const std::shared_ptr<std::set<std::string>>& sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002367{
Ed Tanous62598e32023-07-17 17:06:25 -07002368 BMCWEB_LOG_DEBUG("getChassisCallback enter ");
Nan Zhoubacb2162022-04-06 11:28:32 -07002369
Ed Tanousc1d019a2022-08-06 09:36:06 -07002370 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
2371 for (const std::string& sensor : *sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002372 {
Ed Tanous62598e32023-07-17 17:06:25 -07002373 BMCWEB_LOG_DEBUG("Adding sensor: {}", sensor);
Nan Zhoubacb2162022-04-06 11:28:32 -07002374
2375 sdbusplus::message::object_path path(sensor);
2376 std::string sensorName = path.filename();
2377 if (sensorName.empty())
2378 {
Ed Tanous62598e32023-07-17 17:06:25 -07002379 BMCWEB_LOG_ERROR("Invalid sensor path: {}", sensor);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002380 messages::internalError(asyncResp->res);
Nan Zhoubacb2162022-04-06 11:28:32 -07002381 return;
2382 }
Ed Tanousc1d019a2022-08-06 09:36:06 -07002383 std::string type = path.parent_path().filename();
Janet Adkins1516c212024-08-14 13:22:41 -05002384 std::string id = redfish::sensor_utils::getSensorId(sensorName, type);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002385
Ed Tanous14766872022-03-15 10:44:42 -07002386 nlohmann::json::object_t member;
Ed Tanousef4c65b2023-04-24 15:28:50 -07002387 member["@odata.id"] = boost::urls::format(
2388 "/redfish/v1/Chassis/{}/{}/{}", chassisId, chassisSubNode, id);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002389
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002390 entriesArray.emplace_back(std::move(member));
Nan Zhoubacb2162022-04-06 11:28:32 -07002391 }
2392
Ed Tanousc1d019a2022-08-06 09:36:06 -07002393 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Ed Tanous62598e32023-07-17 17:06:25 -07002394 BMCWEB_LOG_DEBUG("getChassisCallback exit");
Nan Zhoubacb2162022-04-06 11:28:32 -07002395}
Nan Zhoue6bd8462022-06-01 04:35:35 +00002396
Ed Tanousac106bf2023-06-07 09:24:59 -07002397inline void handleSensorCollectionGet(
2398 App& app, const crow::Request& req,
2399 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2400 const std::string& chassisId)
Nan Zhoude167a62022-06-01 04:47:45 +00002401{
2402 query_param::QueryCapabilities capabilities = {
2403 .canDelegateExpandLevel = 1,
2404 };
2405 query_param::Query delegatedQuery;
Ed Tanousac106bf2023-06-07 09:24:59 -07002406 if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
Nan Zhoude167a62022-06-01 04:47:45 +00002407 delegatedQuery, capabilities))
2408 {
2409 return;
2410 }
2411
2412 if (delegatedQuery.expandType != query_param::ExpandType::None)
2413 {
2414 // we perform efficient expand.
Ed Tanousac106bf2023-06-07 09:24:59 -07002415 auto sensorsAsyncResp = std::make_shared<SensorsAsyncResp>(
2416 asyncResp, chassisId, sensors::dbus::sensorPaths,
Janet Adkins0c728b42024-08-29 11:09:10 -05002417 sensors::sensorsNodeStr,
Nan Zhoude167a62022-06-01 04:47:45 +00002418 /*efficientExpand=*/true);
Ed Tanousac106bf2023-06-07 09:24:59 -07002419 getChassisData(sensorsAsyncResp);
Nan Zhoude167a62022-06-01 04:47:45 +00002420
Ed Tanous62598e32023-07-17 17:06:25 -07002421 BMCWEB_LOG_DEBUG(
2422 "SensorCollection doGet exit via efficient expand handler");
Nan Zhoude167a62022-06-01 04:47:45 +00002423 return;
Ed Tanous0bad3202022-06-02 13:53:59 -07002424 }
Nan Zhoude167a62022-06-01 04:47:45 +00002425
Nan Zhoude167a62022-06-01 04:47:45 +00002426 // We get all sensors as hyperlinkes in the chassis (this
2427 // implies we reply on the default query parameters handler)
Janet Adkins0c728b42024-08-29 11:09:10 -05002428 getChassis(asyncResp, chassisId, sensors::sensorsNodeStr, dbus::sensorPaths,
Ed Tanousac106bf2023-06-07 09:24:59 -07002429 std::bind_front(sensors::getChassisCallback, asyncResp,
Janet Adkins0c728b42024-08-29 11:09:10 -05002430 chassisId, sensors::sensorsNodeStr));
Ed Tanousc1d019a2022-08-06 09:36:06 -07002431}
Ed Tanous7f1cc262022-08-09 13:33:57 -07002432
Patrick Williams504af5a2025-02-03 14:29:03 -05002433inline void getSensorFromDbus(
2434 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2435 const std::string& sensorPath,
2436 const ::dbus::utility::MapperGetObject& mapperResponse)
Ed Tanousc1d019a2022-08-06 09:36:06 -07002437{
2438 if (mapperResponse.size() != 1)
2439 {
2440 messages::internalError(asyncResp->res);
2441 return;
2442 }
2443 const auto& valueIface = *mapperResponse.begin();
2444 const std::string& connectionName = valueIface.first;
Ed Tanous62598e32023-07-17 17:06:25 -07002445 BMCWEB_LOG_DEBUG("Looking up {}", connectionName);
2446 BMCWEB_LOG_DEBUG("Path {}", sensorPath);
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +02002447
Ed Tanousdeae6a72024-11-11 21:58:57 -08002448 ::dbus::utility::getAllProperties(
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +02002449 *crow::connections::systemBus, connectionName, sensorPath, "",
Ed Tanousc1d019a2022-08-06 09:36:06 -07002450 [asyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002451 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002452 const ::dbus::utility::DBusPropertiesMap& valuesDict) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002453 if (ec)
2454 {
2455 messages::internalError(asyncResp->res);
2456 return;
2457 }
2458 sdbusplus::message::object_path path(sensorPath);
2459 std::string name = path.filename();
2460 path = path.parent_path();
2461 std::string type = path.filename();
Janet Adkinsc9563602024-08-28 11:37:46 -05002462 sensor_utils::objectPropertiesToJson(
Janet Adkins0c728b42024-08-29 11:09:10 -05002463 name, type, sensor_utils::ChassisSubNode::sensorsNode,
2464 valuesDict, asyncResp->res.jsonValue, nullptr);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002465 });
Nan Zhoude167a62022-06-01 04:47:45 +00002466}
2467
Nan Zhoue6bd8462022-06-01 04:35:35 +00002468inline void handleSensorGet(App& app, const crow::Request& req,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002469 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous677bb752022-09-15 10:52:19 -07002470 const std::string& chassisId,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002471 const std::string& sensorId)
Nan Zhoue6bd8462022-06-01 04:35:35 +00002472{
Ed Tanousc1d019a2022-08-06 09:36:06 -07002473 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Nan Zhoue6bd8462022-06-01 04:35:35 +00002474 {
2475 return;
2476 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002477 std::pair<std::string, std::string> nameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002478 redfish::sensor_utils::splitSensorNameAndType(sensorId);
Ed Tanousc71d6122022-11-29 14:10:32 -08002479 if (nameType.first.empty() || nameType.second.empty())
Ed Tanousc1d019a2022-08-06 09:36:06 -07002480 {
2481 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2482 return;
2483 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002484
Ed Tanousef4c65b2023-04-24 15:28:50 -07002485 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2486 "/redfish/v1/Chassis/{}/Sensors/{}", chassisId, sensorId);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002487
Ed Tanous62598e32023-07-17 17:06:25 -07002488 BMCWEB_LOG_DEBUG("Sensor doGet enter");
Nan Zhoue6bd8462022-06-01 04:35:35 +00002489
George Liu2b731192023-01-11 16:27:13 +08002490 constexpr std::array<std::string_view, 1> interfaces = {
Nan Zhoue6bd8462022-06-01 04:35:35 +00002491 "xyz.openbmc_project.Sensor.Value"};
Ed Tanousc71d6122022-11-29 14:10:32 -08002492 std::string sensorPath = "/xyz/openbmc_project/sensors/" + nameType.first +
2493 '/' + nameType.second;
Nan Zhoue6bd8462022-06-01 04:35:35 +00002494 // Get a list of all of the sensors that implement Sensor.Value
2495 // and get the path and service name associated with the sensor
George Liu2b731192023-01-11 16:27:13 +08002496 ::dbus::utility::getDbusObject(
2497 sensorPath, interfaces,
Myung Baeaec0ec32023-05-31 15:10:01 -05002498 [asyncResp, sensorId,
George Liu2b731192023-01-11 16:27:13 +08002499 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002500 const ::dbus::utility::MapperGetObject& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002501 BMCWEB_LOG_DEBUG("respHandler1 enter");
2502 if (ec == boost::system::errc::io_error)
2503 {
2504 BMCWEB_LOG_WARNING("Sensor not found from getSensorPaths");
2505 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2506 return;
2507 }
2508 if (ec)
2509 {
2510 messages::internalError(asyncResp->res);
2511 BMCWEB_LOG_ERROR(
2512 "Sensor getSensorPaths resp_handler: Dbus error {}", ec);
2513 return;
2514 }
2515 getSensorFromDbus(asyncResp, sensorPath, subtree);
2516 BMCWEB_LOG_DEBUG("respHandler1 exit");
2517 });
Nan Zhoue6bd8462022-06-01 04:35:35 +00002518}
2519
Nan Zhoubacb2162022-04-06 11:28:32 -07002520} // namespace sensors
2521
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002522inline void requestRoutesSensorCollection(App& app)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002523{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002524 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
Ed Tanoused398212021-06-09 17:05:54 -07002525 .privileges(redfish::privileges::getSensorCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002526 .methods(boost::beast::http::verb::get)(
Nan Zhoude167a62022-06-01 04:47:45 +00002527 std::bind_front(sensors::handleSensorCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002528}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002529
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002530inline void requestRoutesSensor(App& app)
2531{
2532 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002533 .privileges(redfish::privileges::getSensor)
Ed Tanous002d39b2022-05-31 08:59:27 -07002534 .methods(boost::beast::http::verb::get)(
Nan Zhoue6bd8462022-06-01 04:35:35 +00002535 std::bind_front(sensors::handleSensorGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002536}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002537
Ed Tanous1abe55e2018-09-05 08:30:59 -07002538} // namespace redfish