blob: 97ee5faac1e20b7aa0bf3867efead5c16c0e916c [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>
Ed Tanousd7857202025-01-28 15:32:26 -080039#include <cstddef>
40#include <cstdint>
41#include <functional>
Nan Zhoufe04d492022-06-22 17:10:41 +000042#include <iterator>
43#include <map>
Ed Tanousd7857202025-01-28 15:32:26 -080044#include <memory>
45#include <optional>
Ed Tanous3544d2a2023-08-06 18:12:20 -070046#include <ranges>
Nan Zhoufe04d492022-06-22 17:10:41 +000047#include <set>
Ed Tanousd7857202025-01-28 15:32:26 -080048#include <span>
Ed Tanous18f8f602023-07-18 10:07:23 -070049#include <string>
George Liu7a1dbc42022-12-07 16:03:22 +080050#include <string_view>
Ed Tanousd7857202025-01-28 15:32:26 -080051#include <unordered_map>
Ed Tanousb5a76932020-09-29 16:16:58 -070052#include <utility>
Ed Tanousabf2add2019-01-22 16:40:12 -080053#include <variant>
Ed Tanousd7857202025-01-28 15:32:26 -080054#include <vector>
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010055
Ed Tanous1abe55e2018-09-05 08:30:59 -070056namespace redfish
57{
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010058
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020059namespace sensors
60{
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020061
Ed Tanous02da7c52022-02-27 00:09:02 -080062// clang-format off
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020063namespace dbus
64{
Ed Tanouscf9e4172022-12-21 09:30:16 -080065constexpr auto powerPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080066 "/xyz/openbmc_project/sensors/voltage",
67 "/xyz/openbmc_project/sensors/power"
68});
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000069
Ed Tanous25b54db2024-04-17 15:40:31 -070070constexpr auto getSensorPaths(){
71 if constexpr(BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM){
72 return std::to_array<std::string_view>({
73 "/xyz/openbmc_project/sensors/power",
74 "/xyz/openbmc_project/sensors/current",
75 "/xyz/openbmc_project/sensors/airflow",
76 "/xyz/openbmc_project/sensors/humidity",
77 "/xyz/openbmc_project/sensors/voltage",
78 "/xyz/openbmc_project/sensors/fan_tach",
79 "/xyz/openbmc_project/sensors/temperature",
80 "/xyz/openbmc_project/sensors/fan_pwm",
81 "/xyz/openbmc_project/sensors/altitude",
82 "/xyz/openbmc_project/sensors/energy",
Zev Weiss44914192025-03-11 07:59:30 +000083 "/xyz/openbmc_project/sensors/liquidflow",
84 "/xyz/openbmc_project/sensors/pressure",
Ed Tanous25b54db2024-04-17 15:40:31 -070085 "/xyz/openbmc_project/sensors/utilization"});
86 } else {
87 return std::to_array<std::string_view>({"/xyz/openbmc_project/sensors/power",
88 "/xyz/openbmc_project/sensors/current",
89 "/xyz/openbmc_project/sensors/airflow",
90 "/xyz/openbmc_project/sensors/humidity",
91 "/xyz/openbmc_project/sensors/utilization"});
92}
93}
94
95constexpr auto sensorPaths = getSensorPaths();
Ed Tanous02da7c52022-02-27 00:09:02 -080096
Ed Tanouscf9e4172022-12-21 09:30:16 -080097constexpr auto thermalPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080098 "/xyz/openbmc_project/sensors/fan_tach",
99 "/xyz/openbmc_project/sensors/temperature",
100 "/xyz/openbmc_project/sensors/fan_pwm"
101});
102
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000103} // namespace dbus
Ed Tanous02da7c52022-02-27 00:09:02 -0800104// clang-format on
105
Janet Adkins0c728b42024-08-29 11:09:10 -0500106constexpr std::string_view powerNodeStr = sensor_utils::chassisSubNodeToString(
107 sensor_utils::ChassisSubNode::powerNode);
108constexpr std::string_view sensorsNodeStr =
109 sensor_utils::chassisSubNodeToString(
110 sensor_utils::ChassisSubNode::sensorsNode);
111constexpr std::string_view thermalNodeStr =
112 sensor_utils::chassisSubNodeToString(
113 sensor_utils::ChassisSubNode::thermalNode);
114
Ed Tanouscf9e4172022-12-21 09:30:16 -0800115using sensorPair =
116 std::pair<std::string_view, std::span<const std::string_view>>;
Ed Tanous02da7c52022-02-27 00:09:02 -0800117static constexpr std::array<sensorPair, 3> paths = {
Janet Adkins0c728b42024-08-29 11:09:10 -0500118 {{sensors::powerNodeStr, dbus::powerPaths},
119 {sensors::sensorsNodeStr, dbus::sensorPaths},
120 {sensors::thermalNodeStr, dbus::thermalPaths}}};
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000121
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200122} // namespace sensors
123
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100124/**
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200125 * SensorsAsyncResp
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100126 * Gathers data needed for response processing after async calls are done
127 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128class SensorsAsyncResp
129{
130 public:
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200131 using DataCompleteCb = std::function<void(
132 const boost::beast::http::status status,
Nan Zhoufe04d492022-06-22 17:10:41 +0000133 const std::map<std::string, std::string>& uriToDbus)>;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200134
135 struct SensorData
136 {
Ed Tanousf836c1d2024-09-06 16:05:11 -0700137 std::string name;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200138 std::string uri;
Ed Tanousf836c1d2024-09-06 16:05:11 -0700139 std::string dbusPath;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200140 };
141
Ed Tanous8a592812022-06-04 09:06:59 -0700142 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800143 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800144 std::span<const std::string_view> typesIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800145 std::string_view subNode) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400146 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
147 chassisSubNode(subNode), efficientExpand(false)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500148 {}
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200149
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200150 // Store extra data about sensor mapping and return it in callback
Ed Tanous8a592812022-06-04 09:06:59 -0700151 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800152 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800153 std::span<const std::string_view> typesIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800154 std::string_view subNode,
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200155 DataCompleteCb&& creationComplete) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400156 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
157 chassisSubNode(subNode), efficientExpand(false),
158 metadata{std::vector<SensorData>()},
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200159 dataComplete{std::move(creationComplete)}
160 {}
161
Nan Zhou928fefb2022-03-28 08:45:00 -0700162 // sensor collections expand
Ed Tanous8a592812022-06-04 09:06:59 -0700163 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
Nan Zhou928fefb2022-03-28 08:45:00 -0700164 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800165 std::span<const std::string_view> typesIn,
Ed Tanous8a592812022-06-04 09:06:59 -0700166 const std::string_view& subNode, bool efficientExpandIn) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400167 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
168 chassisSubNode(subNode), efficientExpand(efficientExpandIn)
Nan Zhou928fefb2022-03-28 08:45:00 -0700169 {}
170
Ed Tanous1abe55e2018-09-05 08:30:59 -0700171 ~SensorsAsyncResp()
172 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800173 if (asyncResp->res.result() ==
174 boost::beast::http::status::internal_server_error)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700175 {
176 // Reset the json object to clear out any data that made it in
177 // before the error happened todo(ed) handle error condition with
178 // proper code
zhanghch058d1b46d2021-04-01 11:18:24 +0800179 asyncResp->res.jsonValue = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700180 }
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200181
182 if (dataComplete && metadata)
183 {
Nan Zhoufe04d492022-06-22 17:10:41 +0000184 std::map<std::string, std::string> map;
zhanghch058d1b46d2021-04-01 11:18:24 +0800185 if (asyncResp->res.result() == boost::beast::http::status::ok)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200186 {
187 for (auto& sensor : *metadata)
188 {
Ed Tanousc1d019a2022-08-06 09:36:06 -0700189 map.emplace(sensor.uri, sensor.dbusPath);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200190 }
191 }
zhanghch058d1b46d2021-04-01 11:18:24 +0800192 dataComplete(asyncResp->res.result(), map);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200193 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700194 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100195
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800196 SensorsAsyncResp(const SensorsAsyncResp&) = delete;
197 SensorsAsyncResp(SensorsAsyncResp&&) = delete;
198 SensorsAsyncResp& operator=(const SensorsAsyncResp&) = delete;
199 SensorsAsyncResp& operator=(SensorsAsyncResp&&) = delete;
200
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200201 void addMetadata(const nlohmann::json& sensorObject,
Ed Tanousc1d019a2022-08-06 09:36:06 -0700202 const std::string& dbusPath)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200203 {
Ed Tanous82b286f2025-05-06 13:29:48 -0700204 if (!metadata)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200205 {
Ed Tanous82b286f2025-05-06 13:29:48 -0700206 return;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200207 }
Ed Tanous82b286f2025-05-06 13:29:48 -0700208 const auto nameIt = sensorObject.find("Name");
James Athappillyd9cca622025-06-13 08:59:46 -0700209 if (nameIt == sensorObject.end())
Ed Tanous82b286f2025-05-06 13:29:48 -0700210 {
211 return;
212 }
213 const auto idIt = sensorObject.find("@odata.id");
James Athappillyd9cca622025-06-13 08:59:46 -0700214 if (idIt == sensorObject.end())
Ed Tanous82b286f2025-05-06 13:29:48 -0700215 {
216 return;
217 }
218 const std::string* name = nameIt->get_ptr<const std::string*>();
219 if (name == nullptr)
220 {
221 return;
222 }
223 const std::string* id = idIt->get_ptr<const std::string*>();
224 if (id == nullptr)
225 {
226 return;
227 }
228 metadata->emplace_back(SensorData{*name, *id, dbusPath});
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200229 }
230
231 void updateUri(const std::string& name, const std::string& uri)
232 {
233 if (metadata)
234 {
235 for (auto& sensor : *metadata)
236 {
237 if (sensor.name == name)
238 {
239 sensor.uri = uri;
240 }
241 }
242 }
243 }
244
zhanghch058d1b46d2021-04-01 11:18:24 +0800245 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200246 const std::string chassisId;
Ed Tanouscf9e4172022-12-21 09:30:16 -0800247 const std::span<const std::string_view> types;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200248 const std::string chassisSubNode;
Nan Zhou928fefb2022-03-28 08:45:00 -0700249 const bool efficientExpand;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200250
251 private:
252 std::optional<std::vector<SensorData>> metadata;
253 DataCompleteCb dataComplete;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100254};
255
Janet Adkinsc9563602024-08-28 11:37:46 -0500256using InventoryItem = sensor_utils::InventoryItem;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500257
258/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530259 * @brief Get objects with connection necessary for sensors
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200260 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100261 * @param sensorNames Sensors retrieved from chassis
262 * @param callback Callback for processing gathered connections
263 */
264template <typename Callback>
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530265void getObjectsWithConnection(
Ed Tanous81ce6092020-12-17 16:54:55 +0000266 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +0000267 const std::shared_ptr<std::set<std::string>>& sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530268 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700269{
Ed Tanous62598e32023-07-17 17:06:25 -0700270 BMCWEB_LOG_DEBUG("getObjectsWithConnection enter");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700271 const std::string path = "/xyz/openbmc_project/sensors";
George Liue99073f2022-12-09 11:06:16 +0800272 constexpr std::array<std::string_view, 1> interfaces = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700273 "xyz.openbmc_project.Sensor.Value"};
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100274
George Liue99073f2022-12-09 11:06:16 +0800275 // Make call to ObjectMapper to find all sensors objects
276 dbus::utility::getSubTree(
277 path, 2, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700278 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
George Liue99073f2022-12-09 11:06:16 +0800279 sensorNames](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700280 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400281 // Response handler for parsing objects subtree
282 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler enter");
283 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700284 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400285 messages::internalError(sensorsAsyncResp->asyncResp->res);
286 BMCWEB_LOG_ERROR(
287 "getObjectsWithConnection resp_handler: Dbus error {}", ec);
288 return;
289 }
290
291 BMCWEB_LOG_DEBUG("Found {} subtrees", subtree.size());
292
293 // Make unique list of connections only for requested sensor types
294 // and found in the chassis
295 std::set<std::string> connections;
296 std::set<std::pair<std::string, std::string>> objectsWithConnection;
297
298 BMCWEB_LOG_DEBUG("sensorNames list count: {}", sensorNames->size());
299 for (const std::string& tsensor : *sensorNames)
300 {
301 BMCWEB_LOG_DEBUG("Sensor to find: {}", tsensor);
302 }
303
304 for (const std::pair<std::string,
305 std::vector<std::pair<
306 std::string, std::vector<std::string>>>>&
307 object : subtree)
308 {
Ed Tanous3d158642025-05-12 14:20:49 -0700309 if (sensorNames->contains(object.first))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700310 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400311 for (const std::pair<std::string, std::vector<std::string>>&
312 objData : object.second)
313 {
314 BMCWEB_LOG_DEBUG("Adding connection: {}",
315 objData.first);
316 connections.insert(objData.first);
317 objectsWithConnection.insert(
318 std::make_pair(object.first, objData.first));
319 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700320 }
321 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400322 BMCWEB_LOG_DEBUG("Found {} connections", connections.size());
323 callback(std::move(connections), std::move(objectsWithConnection));
324 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler exit");
325 });
Ed Tanous62598e32023-07-17 17:06:25 -0700326 BMCWEB_LOG_DEBUG("getObjectsWithConnection exit");
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530327}
328
329/**
330 * @brief Create connections necessary for sensors
331 * @param SensorsAsyncResp Pointer to object holding response data
332 * @param sensorNames Sensors retrieved from chassis
333 * @param callback Callback for processing gathered connections
334 */
335template <typename Callback>
Ed Tanousdaadfb22024-12-20 09:25:54 -0800336void getConnections(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
337 const std::shared_ptr<std::set<std::string>>& sensorNames,
Nan Zhoufe04d492022-06-22 17:10:41 +0000338 Callback&& callback)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530339{
340 auto objectsWithConnectionCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -0700341 [callback = std::forward<Callback>(callback)](
342 const std::set<std::string>& connections,
343 const std::set<std::pair<std::string, std::string>>&
344 /*objectsWithConnection*/) { callback(connections); };
Ed Tanous81ce6092020-12-17 16:54:55 +0000345 getObjectsWithConnection(sensorsAsyncResp, sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530346 std::move(objectsWithConnectionCb));
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100347}
348
349/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700350 * @brief Shrinks the list of sensors for processing
351 * @param SensorsAysncResp The class holding the Redfish response
352 * @param allSensors A list of all the sensors associated to the
353 * chassis element (i.e. baseboard, front panel, etc...)
354 * @param activeSensors A list that is a reduction of the incoming
355 * allSensors list. Eliminate Thermal sensors when a Power request is
356 * made, and eliminate Power sensors when a Thermal request is made.
357 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000358inline void reduceSensorList(
Ed Tanous7f1cc262022-08-09 13:33:57 -0700359 crow::Response& res, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800360 std::span<const std::string_view> sensorTypes,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700361 const std::vector<std::string>* allSensors,
Nan Zhoufe04d492022-06-22 17:10:41 +0000362 const std::shared_ptr<std::set<std::string>>& activeSensors)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700363{
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700364 if ((allSensors == nullptr) || (activeSensors == nullptr))
365 {
Ed Tanous7f1cc262022-08-09 13:33:57 -0700366 messages::resourceNotFound(res, chassisSubNode,
Janet Adkins0c728b42024-08-29 11:09:10 -0500367 chassisSubNode == sensors::thermalNodeStr
Ed Tanous7f1cc262022-08-09 13:33:57 -0700368 ? "Temperatures"
369 : "Voltages");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700370
371 return;
372 }
373 if (allSensors->empty())
374 {
375 // Nothing to do, the activeSensors object is also empty
376 return;
377 }
378
Ed Tanous7f1cc262022-08-09 13:33:57 -0700379 for (std::string_view type : sensorTypes)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700380 {
381 for (const std::string& sensor : *allSensors)
382 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700383 if (sensor.starts_with(type))
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700384 {
385 activeSensors->emplace(sensor);
386 }
387 }
388 }
389}
390
Ed Tanous7f1cc262022-08-09 13:33:57 -0700391/*
392 *Populates the top level collection for a given subnode. Populates
393 *SensorCollection, Power, or Thermal schemas.
394 *
395 * */
396inline void populateChassisNode(nlohmann::json& jsonValue,
397 std::string_view chassisSubNode)
398{
Janet Adkins0c728b42024-08-29 11:09:10 -0500399 if (chassisSubNode == sensors::powerNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700400 {
401 jsonValue["@odata.type"] = "#Power.v1_5_2.Power";
402 }
Janet Adkins0c728b42024-08-29 11:09:10 -0500403 else if (chassisSubNode == sensors::thermalNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700404 {
405 jsonValue["@odata.type"] = "#Thermal.v1_4_0.Thermal";
406 jsonValue["Fans"] = nlohmann::json::array();
407 jsonValue["Temperatures"] = nlohmann::json::array();
408 }
Janet Adkins0c728b42024-08-29 11:09:10 -0500409 else if (chassisSubNode == sensors::sensorsNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700410 {
411 jsonValue["@odata.type"] = "#SensorCollection.SensorCollection";
412 jsonValue["Description"] = "Collection of Sensors for this Chassis";
413 jsonValue["Members"] = nlohmann::json::array();
414 jsonValue["Members@odata.count"] = 0;
415 }
416
Janet Adkins0c728b42024-08-29 11:09:10 -0500417 if (chassisSubNode != sensors::sensorsNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700418 {
419 jsonValue["Id"] = chassisSubNode;
420 }
421 jsonValue["Name"] = chassisSubNode;
422}
423
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700424/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100425 * @brief Retrieves requested chassis sensors and redundancy data from DBus .
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200426 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100427 * @param callback Callback for next step in gathered sensor processing
428 */
429template <typename Callback>
Ed Tanous7f1cc262022-08-09 13:33:57 -0700430void getChassis(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
431 std::string_view chassisId, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800432 std::span<const std::string_view> sensorTypes,
433 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700434{
Ed Tanous62598e32023-07-17 17:06:25 -0700435 BMCWEB_LOG_DEBUG("getChassis enter");
George Liu7a1dbc42022-12-07 16:03:22 +0800436
437 // Get the Chassis Collection
438 dbus::utility::getSubTreePaths(
Myung Bae3f95a272024-03-13 07:32:02 -0700439 "/xyz/openbmc_project/inventory", 0, chassisInterfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700440 [callback = std::forward<Callback>(callback), asyncResp,
Ed Tanous7f1cc262022-08-09 13:33:57 -0700441 chassisIdStr{std::string(chassisId)},
Ed Tanous4e0d8782024-09-06 15:16:41 -0700442 chassisSubNode{std::string(chassisSubNode)},
443 sensorTypes](const boost::system::error_code& ec,
444 const dbus::utility::MapperGetSubTreePathsResponse&
445 chassisPaths) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400446 BMCWEB_LOG_DEBUG("getChassis respHandler enter");
447 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700448 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400449 BMCWEB_LOG_ERROR("getChassis respHandler DBUS error: {}", ec);
450 messages::internalError(asyncResp->res);
451 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700452 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400453 const std::string* chassisPath = nullptr;
454 for (const std::string& chassis : chassisPaths)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700455 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400456 sdbusplus::message::object_path path(chassis);
457 std::string chassisName = path.filename();
458 if (chassisName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700459 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400460 BMCWEB_LOG_ERROR("Failed to find '/' in {}", chassis);
461 continue;
462 }
463 if (chassisName == chassisIdStr)
464 {
465 chassisPath = &chassis;
466 break;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700467 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700468 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400469 if (chassisPath == nullptr)
470 {
471 messages::resourceNotFound(asyncResp->res, "Chassis",
472 chassisIdStr);
473 return;
474 }
475 populateChassisNode(asyncResp->res.jsonValue, chassisSubNode);
476
477 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
478 "/redfish/v1/Chassis/{}/{}", chassisIdStr, chassisSubNode);
479
480 // Get the list of all sensors for this Chassis element
481 std::string sensorPath = *chassisPath + "/all_sensors";
482 dbus::utility::getAssociationEndPoints(
Ed Tanous4e0d8782024-09-06 15:16:41 -0700483 sensorPath, [asyncResp, chassisSubNode, sensorTypes,
484 callback = std::forward<Callback>(callback)](
485 const boost::system::error_code& ec2,
486 const dbus::utility::MapperEndPoints&
487 nodeSensorList) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400488 if (ec2)
489 {
490 if (ec2.value() != EBADR)
491 {
492 messages::internalError(asyncResp->res);
493 return;
494 }
495 }
496 const std::shared_ptr<std::set<std::string>>
497 culledSensorList =
498 std::make_shared<std::set<std::string>>();
499 reduceSensorList(asyncResp->res, chassisSubNode,
500 sensorTypes, &nodeSensorList,
501 culledSensorList);
502 BMCWEB_LOG_DEBUG("Finishing with {}",
503 culledSensorList->size());
504 callback(culledSensorList);
505 });
George Liu7a1dbc42022-12-07 16:03:22 +0800506 });
Ed Tanous62598e32023-07-17 17:06:25 -0700507 BMCWEB_LOG_DEBUG("getChassis exit");
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100508}
509
510/**
Ed Tanous1d7c0052022-08-09 12:32:26 -0700511 * @brief Builds a json sensor representation of a sensor.
512 * @param sensorName The name of the sensor to be built
513 * @param sensorType The type (temperature, fan_tach, etc) of the sensor to
514 * build
Ed Tanous8ece0e42024-01-02 13:16:50 -0800515 * @param chassisSubNode The subnode (thermal, sensor, etc) of the sensor
Ed Tanous1d7c0052022-08-09 12:32:26 -0700516 * @param interfacesDict A dictionary of the interfaces and properties of said
517 * interfaces to be built from
518 * @param sensorJson The json object to fill
519 * @param inventoryItem D-Bus inventory item associated with the sensor. Will
520 * be nullptr if no associated inventory item was found.
521 */
522inline void objectInterfacesToJson(
523 const std::string& sensorName, const std::string& sensorType,
Janet Adkins0c728b42024-08-29 11:09:10 -0500524 const sensor_utils::ChassisSubNode chassisSubNode,
Michael Shen80f79a42023-08-24 13:41:53 +0000525 const dbus::utility::DBusInterfacesMap& interfacesDict,
Ed Tanous1d7c0052022-08-09 12:32:26 -0700526 nlohmann::json& sensorJson, InventoryItem* inventoryItem)
527{
Ed Tanous1d7c0052022-08-09 12:32:26 -0700528 for (const auto& [interface, valuesDict] : interfacesDict)
529 {
Janet Adkinsc9563602024-08-28 11:37:46 -0500530 sensor_utils::objectPropertiesToJson(
531 sensorName, sensorType, chassisSubNode, valuesDict, sensorJson,
532 inventoryItem);
Ed Tanous1d7c0052022-08-09 12:32:26 -0700533 }
Ed Tanous62598e32023-07-17 17:06:25 -0700534 BMCWEB_LOG_DEBUG("Added sensor {}", sensorName);
Ed Tanous1d7c0052022-08-09 12:32:26 -0700535}
536
Ed Tanousb5a76932020-09-29 16:16:58 -0700537inline void populateFanRedundancy(
538 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
James Feist8bd25cc2019-03-15 15:14:00 -0700539{
George Liue99073f2022-12-09 11:06:16 +0800540 constexpr std::array<std::string_view, 1> interfaces = {
541 "xyz.openbmc_project.Control.FanRedundancy"};
542 dbus::utility::getSubTree(
543 "/xyz/openbmc_project/control", 2, interfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800544 [sensorsAsyncResp](
George Liue99073f2022-12-09 11:06:16 +0800545 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800546 const dbus::utility::MapperGetSubTreeResponse& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400547 if (ec)
James Feist8bd25cc2019-03-15 15:14:00 -0700548 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400549 return; // don't have to have this interface
James Feist8bd25cc2019-03-15 15:14:00 -0700550 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400551 for (const std::pair<std::string, dbus::utility::MapperServiceMap>&
552 pathPair : resp)
553 {
554 const std::string& path = pathPair.first;
555 const dbus::utility::MapperServiceMap& objDict =
556 pathPair.second;
557 if (objDict.empty())
James Feist8bd25cc2019-03-15 15:14:00 -0700558 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400559 continue; // this should be impossible
James Feist8bd25cc2019-03-15 15:14:00 -0700560 }
561
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400562 const std::string& owner = objDict.begin()->first;
563 dbus::utility::getAssociationEndPoints(
564 path + "/chassis",
565 [path, owner, sensorsAsyncResp](
566 const boost::system::error_code& ec2,
567 const dbus::utility::MapperEndPoints& endpoints) {
568 if (ec2)
James Feist8bd25cc2019-03-15 15:14:00 -0700569 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400570 return; // if they don't have an association we
571 // can't tell what chassis is
James Feist8bd25cc2019-03-15 15:14:00 -0700572 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400573 auto found = std::ranges::find_if(
574 endpoints,
575 [sensorsAsyncResp](const std::string& entry) {
576 return entry.find(
577 sensorsAsyncResp->chassisId) !=
578 std::string::npos;
579 });
580
581 if (found == endpoints.end())
James Feist8bd25cc2019-03-15 15:14:00 -0700582 {
583 return;
584 }
Ed Tanousdeae6a72024-11-11 21:58:57 -0800585 dbus::utility::getAllProperties(
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400586 *crow::connections::systemBus, owner, path,
587 "xyz.openbmc_project.Control.FanRedundancy",
588 [path, sensorsAsyncResp](
589 const boost::system::error_code& ec3,
590 const dbus::utility::DBusPropertiesMap& ret) {
591 if (ec3)
592 {
593 return; // don't have to have this
594 // interface
595 }
James Feist8bd25cc2019-03-15 15:14:00 -0700596
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400597 const uint8_t* allowedFailures = nullptr;
598 const std::vector<std::string>* collection =
599 nullptr;
600 const std::string* status = nullptr;
James Feist8bd25cc2019-03-15 15:14:00 -0700601
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400602 const bool success =
603 sdbusplus::unpackPropertiesNoThrow(
604 dbus_utils::UnpackErrorPrinter(), ret,
605 "AllowedFailures", allowedFailures,
606 "Collection", collection, "Status",
607 status);
James Feist8bd25cc2019-03-15 15:14:00 -0700608
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400609 if (!success)
610 {
611 messages::internalError(
612 sensorsAsyncResp->asyncResp->res);
613 return;
614 }
615
616 if (allowedFailures == nullptr ||
617 collection == nullptr || status == nullptr)
618 {
619 BMCWEB_LOG_ERROR(
620 "Invalid redundancy interface");
621 messages::internalError(
622 sensorsAsyncResp->asyncResp->res);
623 return;
624 }
625
626 sdbusplus::message::object_path objectPath(
627 path);
628 std::string name = objectPath.filename();
629 if (name.empty())
630 {
631 // this should be impossible
632 messages::internalError(
633 sensorsAsyncResp->asyncResp->res);
634 return;
635 }
636 std::ranges::replace(name, '_', ' ');
637
638 std::string health;
639
640 if (status->ends_with("Full"))
641 {
642 health = "OK";
643 }
644 else if (status->ends_with("Degraded"))
645 {
646 health = "Warning";
647 }
648 else
649 {
650 health = "Critical";
651 }
652 nlohmann::json::array_t redfishCollection;
653 const auto& fanRedfish =
654 sensorsAsyncResp->asyncResp->res
655 .jsonValue["Fans"];
656 for (const std::string& item : *collection)
657 {
658 sdbusplus::message::object_path itemPath(
659 item);
660 std::string itemName = itemPath.filename();
661 if (itemName.empty())
662 {
663 continue;
664 }
665 /*
666 todo(ed): merge patch that fixes the names
667 std::replace(itemName.begin(),
668 itemName.end(), '_', ' ');*/
669 auto schemaItem = std::ranges::find_if(
670 fanRedfish,
671 [itemName](const nlohmann::json& fan) {
672 return fan["Name"] == itemName;
673 });
674 if (schemaItem != fanRedfish.end())
675 {
676 nlohmann::json::object_t collectionId;
677 collectionId["@odata.id"] =
678 (*schemaItem)["@odata.id"];
679 redfishCollection.emplace_back(
680 std::move(collectionId));
681 }
682 else
683 {
684 BMCWEB_LOG_ERROR(
685 "failed to find fan in schema");
686 messages::internalError(
687 sensorsAsyncResp->asyncResp->res);
688 return;
689 }
690 }
691
692 size_t minNumNeeded =
693 collection->empty()
694 ? 0
695 : collection->size() - *allowedFailures;
696 nlohmann::json& jResp =
697 sensorsAsyncResp->asyncResp->res
698 .jsonValue["Redundancy"];
699
700 nlohmann::json::object_t redundancy;
701 boost::urls::url url = boost::urls::format(
702 "/redfish/v1/Chassis/{}/{}",
703 sensorsAsyncResp->chassisId,
704 sensorsAsyncResp->chassisSubNode);
705 url.set_fragment(
706 ("/Redundancy"_json_pointer / jResp.size())
707 .to_string());
708 redundancy["@odata.id"] = std::move(url);
709 redundancy["@odata.type"] =
710 "#Redundancy.v1_3_2.Redundancy";
711 redundancy["MinNumNeeded"] = minNumNeeded;
712 redundancy["Mode"] =
713 redundancy::RedundancyType::NPlusM;
714 redundancy["Name"] = name;
715 redundancy["RedundancySet"] = redfishCollection;
716 redundancy["Status"]["Health"] = health;
717 redundancy["Status"]["State"] =
718 resource::State::Enabled;
719
720 jResp.emplace_back(std::move(redundancy));
721 });
722 });
723 }
724 });
James Feist8bd25cc2019-03-15 15:14:00 -0700725}
726
Patrick Williams504af5a2025-02-03 14:29:03 -0500727inline void sortJSONResponse(
728 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700729{
zhanghch058d1b46d2021-04-01 11:18:24 +0800730 nlohmann::json& response = sensorsAsyncResp->asyncResp->res.jsonValue;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700731 std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
Janet Adkins0c728b42024-08-29 11:09:10 -0500732 if (sensorsAsyncResp->chassisSubNode == sensors::powerNodeStr)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700733 {
734 sensorHeaders = {"Voltages", "PowerSupplies"};
735 }
736 for (const std::string& sensorGroup : sensorHeaders)
737 {
738 nlohmann::json::iterator entry = response.find(sensorGroup);
Ed Tanous4e196b92024-09-27 17:45:09 -0700739 if (entry == response.end())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700740 {
Ed Tanous4e196b92024-09-27 17:45:09 -0700741 continue;
742 }
743 nlohmann::json::array_t* arr =
744 entry->get_ptr<nlohmann::json::array_t*>();
745 if (arr == nullptr)
746 {
747 continue;
748 }
749 json_util::sortJsonArrayByKey(*arr, "Name");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700750
Ed Tanous4e196b92024-09-27 17:45:09 -0700751 // add the index counts to the end of each entry
752 size_t count = 0;
753 for (nlohmann::json& sensorJson : *entry)
754 {
755 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
756 if (odata == sensorJson.end())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700757 {
Ed Tanous4e196b92024-09-27 17:45:09 -0700758 continue;
759 }
Ed Tanous82b286f2025-05-06 13:29:48 -0700760 const auto nameIt = sensorJson.find("Name");
761 if (nameIt == sensorJson.end())
Ed Tanous4e196b92024-09-27 17:45:09 -0700762 {
Ed Tanous82b286f2025-05-06 13:29:48 -0700763 continue;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700764 }
Ed Tanous82b286f2025-05-06 13:29:48 -0700765 std::string* value = odata->get_ptr<std::string*>();
766 if (value == nullptr)
767 {
768 continue;
769 }
770 const std::string* name = nameIt->get_ptr<const std::string*>();
771 if (name == nullptr)
772 {
773 continue;
774 }
775 *value += "/" + std::to_string(count);
776 sensorJson["MemberId"] = std::to_string(count);
777 count++;
778 sensorsAsyncResp->updateUri(*name, *value);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700779 }
780 }
781}
782
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100783/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500784 * @brief Finds the inventory item with the specified object path.
785 * @param inventoryItems D-Bus inventory items associated with sensors.
786 * @param invItemObjPath D-Bus object path of inventory item.
787 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500788 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000789inline InventoryItem* findInventoryItem(
Ed Tanousb5a76932020-09-29 16:16:58 -0700790 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500791 const std::string& invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500792{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500793 for (InventoryItem& inventoryItem : *inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500794 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500795 if (inventoryItem.objectPath == invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500796 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500797 return &inventoryItem;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500798 }
799 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500800 return nullptr;
801}
802
803/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500804 * @brief Finds the inventory item associated with the specified sensor.
805 * @param inventoryItems D-Bus inventory items associated with sensors.
806 * @param sensorObjPath D-Bus object path of sensor.
807 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500808 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000809inline InventoryItem* findInventoryItemForSensor(
Ed Tanousb5a76932020-09-29 16:16:58 -0700810 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500811 const std::string& sensorObjPath)
812{
813 for (InventoryItem& inventoryItem : *inventoryItems)
814 {
Ed Tanousdb0d36e2023-06-30 10:37:05 -0700815 if (inventoryItem.sensors.contains(sensorObjPath))
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500816 {
817 return &inventoryItem;
818 }
819 }
820 return nullptr;
821}
822
823/**
Anthony Wilsond5005492019-07-31 16:34:17 -0500824 * @brief Finds the inventory item associated with the specified led path.
825 * @param inventoryItems D-Bus inventory items associated with sensors.
826 * @param ledObjPath D-Bus object path of led.
827 * @return Inventory item within vector, or nullptr if no match found.
828 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400829inline InventoryItem* findInventoryItemForLed(
830 std::vector<InventoryItem>& inventoryItems, const std::string& ledObjPath)
Anthony Wilsond5005492019-07-31 16:34:17 -0500831{
832 for (InventoryItem& inventoryItem : inventoryItems)
833 {
834 if (inventoryItem.ledObjectPath == ledObjPath)
835 {
836 return &inventoryItem;
837 }
838 }
839 return nullptr;
840}
841
842/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500843 * @brief Adds inventory item and associated sensor to specified vector.
844 *
845 * Adds a new InventoryItem to the vector if necessary. Searches for an
846 * existing InventoryItem with the specified object path. If not found, one is
847 * added to the vector.
848 *
849 * Next, the specified sensor is added to the set of sensors associated with the
850 * InventoryItem.
851 *
852 * @param inventoryItems D-Bus inventory items associated with sensors.
853 * @param invItemObjPath D-Bus object path of inventory item.
854 * @param sensorObjPath D-Bus object path of sensor
855 */
Ed Tanousb5a76932020-09-29 16:16:58 -0700856inline void addInventoryItem(
857 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
858 const std::string& invItemObjPath, const std::string& sensorObjPath)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500859{
860 // Look for inventory item in vector
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400861 InventoryItem* inventoryItem =
862 findInventoryItem(inventoryItems, invItemObjPath);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500863
864 // If inventory item doesn't exist in vector, add it
865 if (inventoryItem == nullptr)
866 {
867 inventoryItems->emplace_back(invItemObjPath);
868 inventoryItem = &(inventoryItems->back());
869 }
870
871 // Add sensor to set of sensors associated with inventory item
872 inventoryItem->sensors.emplace(sensorObjPath);
873}
874
875/**
876 * @brief Stores D-Bus data in the specified inventory item.
877 *
878 * Finds D-Bus data in the specified map of interfaces. Stores the data in the
879 * specified InventoryItem.
880 *
881 * This data is later used to provide sensor property values in the JSON
882 * response.
883 *
884 * @param inventoryItem Inventory item where data will be stored.
885 * @param interfacesDict Map containing D-Bus interfaces and their properties
886 * for the specified inventory item.
887 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000888inline void storeInventoryItemData(
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500889 InventoryItem& inventoryItem,
Michael Shen80f79a42023-08-24 13:41:53 +0000890 const dbus::utility::DBusInterfacesMap& interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500891{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500892 // Get properties from Inventory.Item interface
Ed Tanous711ac7a2021-12-20 09:34:41 -0800893
Ed Tanous9eb808c2022-01-25 10:19:23 -0800894 for (const auto& [interface, values] : interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500895 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800896 if (interface == "xyz.openbmc_project.Inventory.Item")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500897 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800898 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500899 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800900 if (name == "Present")
901 {
902 const bool* value = std::get_if<bool>(&dbusValue);
903 if (value != nullptr)
904 {
905 inventoryItem.isPresent = *value;
906 }
907 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500908 }
909 }
Ed Tanous711ac7a2021-12-20 09:34:41 -0800910 // Check if Inventory.Item.PowerSupply interface is present
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500911
Ed Tanous711ac7a2021-12-20 09:34:41 -0800912 if (interface == "xyz.openbmc_project.Inventory.Item.PowerSupply")
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500913 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800914 inventoryItem.isPowerSupply = true;
915 }
916
917 // Get properties from Inventory.Decorator.Asset interface
918 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
919 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800920 for (const auto& [name, dbusValue] : values)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500921 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800922 if (name == "Manufacturer")
923 {
924 const std::string* value =
925 std::get_if<std::string>(&dbusValue);
926 if (value != nullptr)
927 {
928 inventoryItem.manufacturer = *value;
929 }
930 }
931 if (name == "Model")
932 {
933 const std::string* value =
934 std::get_if<std::string>(&dbusValue);
935 if (value != nullptr)
936 {
937 inventoryItem.model = *value;
938 }
939 }
940 if (name == "SerialNumber")
941 {
942 const std::string* value =
943 std::get_if<std::string>(&dbusValue);
944 if (value != nullptr)
945 {
946 inventoryItem.serialNumber = *value;
947 }
948 }
949 if (name == "PartNumber")
950 {
951 const std::string* value =
952 std::get_if<std::string>(&dbusValue);
953 if (value != nullptr)
954 {
955 inventoryItem.partNumber = *value;
956 }
957 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500958 }
959 }
960
Ed Tanous711ac7a2021-12-20 09:34:41 -0800961 if (interface ==
962 "xyz.openbmc_project.State.Decorator.OperationalStatus")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500963 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800964 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500965 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800966 if (name == "Functional")
967 {
968 const bool* value = std::get_if<bool>(&dbusValue);
969 if (value != nullptr)
970 {
971 inventoryItem.isFunctional = *value;
972 }
973 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500974 }
975 }
976 }
977}
978
979/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500980 * @brief Gets D-Bus data for inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500981 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500982 * Uses the specified connections (services) to obtain D-Bus data for inventory
983 * items associated with sensors. Stores the resulting data in the
984 * inventoryItems vector.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500985 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500986 * This data is later used to provide sensor property values in the JSON
987 * response.
988 *
989 * Finds the inventory item data asynchronously. Invokes callback when data has
990 * been obtained.
991 *
992 * The callback must have the following signature:
993 * @code
Anthony Wilsond5005492019-07-31 16:34:17 -0500994 * callback(void)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500995 * @endcode
996 *
997 * This function is called recursively, obtaining data asynchronously from one
998 * connection in each call. This ensures the callback is not invoked until the
999 * last asynchronous function has completed.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001000 *
1001 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001002 * @param inventoryItems D-Bus inventory items associated with sensors.
1003 * @param invConnections Connections that provide data for the inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001004 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001005 * @param callback Callback to invoke when inventory data has been obtained.
1006 * @param invConnectionsIndex Current index in invConnections. Only specified
1007 * in recursive calls to this function.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001008 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001009template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001010void getInventoryItemsData(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001011 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1012 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
1013 const std::shared_ptr<std::set<std::string>>& invConnections,
1014 Callback&& callback, size_t invConnectionsIndex = 0)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001015{
Ed Tanous62598e32023-07-17 17:06:25 -07001016 BMCWEB_LOG_DEBUG("getInventoryItemsData enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001017
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001018 // If no more connections left, call callback
1019 if (invConnectionsIndex >= invConnections->size())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001020 {
Anthony Wilsond5005492019-07-31 16:34:17 -05001021 callback();
Ed Tanous62598e32023-07-17 17:06:25 -07001022 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001023 return;
1024 }
1025
1026 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +00001027 auto it = invConnections->begin();
1028 std::advance(it, invConnectionsIndex);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001029 if (it != invConnections->end())
1030 {
1031 const std::string& invConnection = *it;
1032
George Liu5eb468d2023-06-20 17:03:24 +08001033 // Get all object paths and their interfaces for current connection
1034 sdbusplus::message::object_path path("/xyz/openbmc_project/inventory");
1035 dbus::utility::getManagedObjects(
1036 invConnection, path,
1037 [sensorsAsyncResp, inventoryItems, invConnections,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001038 callback = std::forward<Callback>(callback), invConnectionsIndex](
George Liu5eb468d2023-06-20 17:03:24 +08001039 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001040 const dbus::utility::ManagedObjectType& resp) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001041 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler enter");
1042 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001043 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001044 BMCWEB_LOG_ERROR(
1045 "getInventoryItemsData respHandler DBus error {}", ec);
1046 messages::internalError(sensorsAsyncResp->asyncResp->res);
1047 return;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001048 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001049
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001050 // Loop through returned object paths
1051 for (const auto& objDictEntry : resp)
1052 {
1053 const std::string& objPath =
1054 static_cast<const std::string&>(objDictEntry.first);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001055
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001056 // If this object path is one of the specified inventory
1057 // items
1058 InventoryItem* inventoryItem =
1059 findInventoryItem(inventoryItems, objPath);
1060 if (inventoryItem != nullptr)
1061 {
1062 // Store inventory data in InventoryItem
1063 storeInventoryItemData(*inventoryItem,
1064 objDictEntry.second);
1065 }
1066 }
1067
1068 // Recurse to get inventory item data from next connection
1069 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1070 invConnections, std::move(callback),
1071 invConnectionsIndex + 1);
1072
1073 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler exit");
1074 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001075 }
1076
Ed Tanous62598e32023-07-17 17:06:25 -07001077 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001078}
1079
1080/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001081 * @brief Gets connections that provide D-Bus data for inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001082 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001083 * Gets the D-Bus connections (services) that provide data for the inventory
1084 * items that are associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001085 *
1086 * Finds the connections asynchronously. Invokes callback when information has
1087 * been obtained.
1088 *
1089 * The callback must have the following signature:
1090 * @code
Nan Zhoufe04d492022-06-22 17:10:41 +00001091 * callback(std::shared_ptr<std::set<std::string>> invConnections)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001092 * @endcode
1093 *
1094 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001095 * @param inventoryItems D-Bus inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001096 * @param callback Callback to invoke when connections have been obtained.
1097 */
1098template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001099void getInventoryItemsConnections(
Ed Tanousb5a76932020-09-29 16:16:58 -07001100 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1101 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001102 Callback&& callback)
1103{
Ed Tanous62598e32023-07-17 17:06:25 -07001104 BMCWEB_LOG_DEBUG("getInventoryItemsConnections enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001105
1106 const std::string path = "/xyz/openbmc_project/inventory";
George Liue99073f2022-12-09 11:06:16 +08001107 constexpr std::array<std::string_view, 4> interfaces = {
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001108 "xyz.openbmc_project.Inventory.Item",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001109 "xyz.openbmc_project.Inventory.Item.PowerSupply",
1110 "xyz.openbmc_project.Inventory.Decorator.Asset",
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001111 "xyz.openbmc_project.State.Decorator.OperationalStatus"};
1112
George Liue99073f2022-12-09 11:06:16 +08001113 // Make call to ObjectMapper to find all inventory items
1114 dbus::utility::getSubTree(
1115 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001116 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001117 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001118 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001119 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001120 // Response handler for parsing output from GetSubTree
1121 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler enter");
1122 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001123 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001124 messages::internalError(sensorsAsyncResp->asyncResp->res);
1125 BMCWEB_LOG_ERROR(
1126 "getInventoryItemsConnections respHandler DBus error {}",
1127 ec);
1128 return;
1129 }
1130
1131 // Make unique list of connections for desired inventory items
1132 std::shared_ptr<std::set<std::string>> invConnections =
1133 std::make_shared<std::set<std::string>>();
1134
1135 // Loop through objects from GetSubTree
1136 for (const std::pair<std::string,
1137 std::vector<std::pair<
1138 std::string, std::vector<std::string>>>>&
1139 object : subtree)
1140 {
1141 // Check if object path is one of the specified inventory items
1142 const std::string& objPath = object.first;
1143 if (findInventoryItem(inventoryItems, objPath) != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001144 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001145 // Store all connections to inventory item
1146 for (const std::pair<std::string, std::vector<std::string>>&
1147 objData : object.second)
1148 {
1149 const std::string& invConnection = objData.first;
1150 invConnections->insert(invConnection);
1151 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001152 }
1153 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001154
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001155 callback(invConnections);
1156 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler exit");
1157 });
Ed Tanous62598e32023-07-17 17:06:25 -07001158 BMCWEB_LOG_DEBUG("getInventoryItemsConnections exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001159}
1160
1161/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001162 * @brief Gets associations from sensors to inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001163 *
1164 * Looks for ObjectMapper associations from the specified sensors to related
Anthony Wilsond5005492019-07-31 16:34:17 -05001165 * inventory items. Then finds the associations from those inventory items to
1166 * their LEDs, if any.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001167 *
1168 * Finds the inventory items asynchronously. Invokes callback when information
1169 * has been obtained.
1170 *
1171 * The callback must have the following signature:
1172 * @code
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001173 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001174 * @endcode
1175 *
1176 * @param sensorsAsyncResp Pointer to object holding response data.
1177 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001178 * implements ObjectManager.
1179 * @param callback Callback to invoke when inventory items have been obtained.
1180 */
1181template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001182void getInventoryItemAssociations(
Ed Tanousb5a76932020-09-29 16:16:58 -07001183 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001184 const std::shared_ptr<std::set<std::string>>& sensorNames,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001185 Callback&& callback)
1186{
Ed Tanous62598e32023-07-17 17:06:25 -07001187 BMCWEB_LOG_DEBUG("getInventoryItemAssociations enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001188
George Liu5eb468d2023-06-20 17:03:24 +08001189 // Call GetManagedObjects on the ObjectMapper to get all associations
1190 sdbusplus::message::object_path path("/");
1191 dbus::utility::getManagedObjects(
1192 "xyz.openbmc_project.ObjectMapper", path,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001193 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001194 sensorNames](const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001195 const dbus::utility::ManagedObjectType& resp) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001196 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler enter");
1197 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001198 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001199 BMCWEB_LOG_ERROR(
1200 "getInventoryItemAssociations respHandler DBus error {}",
1201 ec);
1202 messages::internalError(sensorsAsyncResp->asyncResp->res);
1203 return;
1204 }
1205
1206 // Create vector to hold list of inventory items
1207 std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1208 std::make_shared<std::vector<InventoryItem>>();
1209
1210 // Loop through returned object paths
1211 std::string sensorAssocPath;
1212 sensorAssocPath.reserve(128); // avoid memory allocations
1213 for (const auto& objDictEntry : resp)
1214 {
1215 const std::string& objPath =
1216 static_cast<const std::string&>(objDictEntry.first);
1217
1218 // If path is inventory association for one of the specified
1219 // sensors
1220 for (const std::string& sensorName : *sensorNames)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001221 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001222 sensorAssocPath = sensorName;
1223 sensorAssocPath += "/inventory";
1224 if (objPath == sensorAssocPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001225 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001226 // Get Association interface for object path
1227 for (const auto& [interface, values] :
1228 objDictEntry.second)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001229 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001230 if (interface == "xyz.openbmc_project.Association")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001231 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001232 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001233 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001234 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001235 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001236 const std::vector<std::string>*
1237 endpoints = std::get_if<
1238 std::vector<std::string>>(
1239 &value);
1240 if ((endpoints != nullptr) &&
1241 !endpoints->empty())
1242 {
1243 // Add inventory item to vector
1244 const std::string& invItemPath =
1245 endpoints->front();
1246 addInventoryItem(inventoryItems,
1247 invItemPath,
1248 sensorName);
1249 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001250 }
1251 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001252 }
1253 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001254 break;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001255 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001256 }
1257 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001258
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001259 // Now loop through the returned object paths again, this time to
1260 // find the leds associated with the inventory items we just found
1261 std::string inventoryAssocPath;
1262 inventoryAssocPath.reserve(128); // avoid memory allocations
1263 for (const auto& objDictEntry : resp)
Anthony Wilsond5005492019-07-31 16:34:17 -05001264 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001265 const std::string& objPath =
1266 static_cast<const std::string&>(objDictEntry.first);
1267
1268 for (InventoryItem& inventoryItem : *inventoryItems)
Anthony Wilsond5005492019-07-31 16:34:17 -05001269 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001270 inventoryAssocPath = inventoryItem.objectPath;
1271 inventoryAssocPath += "/leds";
1272 if (objPath == inventoryAssocPath)
Anthony Wilsond5005492019-07-31 16:34:17 -05001273 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001274 for (const auto& [interface, values] :
1275 objDictEntry.second)
Anthony Wilsond5005492019-07-31 16:34:17 -05001276 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001277 if (interface == "xyz.openbmc_project.Association")
Anthony Wilsond5005492019-07-31 16:34:17 -05001278 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001279 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001280 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001281 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001282 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001283 const std::vector<std::string>*
1284 endpoints = std::get_if<
1285 std::vector<std::string>>(
1286 &value);
1287 if ((endpoints != nullptr) &&
1288 !endpoints->empty())
1289 {
1290 // Add inventory item to vector
1291 // Store LED path in inventory item
1292 const std::string& ledPath =
1293 endpoints->front();
1294 inventoryItem.ledObjectPath =
1295 ledPath;
1296 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001297 }
1298 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001299 }
1300 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001301
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001302 break;
1303 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001304 }
1305 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001306 callback(inventoryItems);
1307 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler exit");
1308 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001309
Ed Tanous62598e32023-07-17 17:06:25 -07001310 BMCWEB_LOG_DEBUG("getInventoryItemAssociations exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001311}
1312
1313/**
Anthony Wilsond5005492019-07-31 16:34:17 -05001314 * @brief Gets D-Bus data for inventory item leds associated with sensors.
1315 *
1316 * Uses the specified connections (services) to obtain D-Bus data for inventory
1317 * item leds associated with sensors. Stores the resulting data in the
1318 * inventoryItems vector.
1319 *
1320 * This data is later used to provide sensor property values in the JSON
1321 * response.
1322 *
1323 * Finds the inventory item led data asynchronously. Invokes callback when data
1324 * has been obtained.
1325 *
1326 * The callback must have the following signature:
1327 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001328 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001329 * @endcode
1330 *
1331 * This function is called recursively, obtaining data asynchronously from one
1332 * connection in each call. This ensures the callback is not invoked until the
1333 * last asynchronous function has completed.
1334 *
1335 * @param sensorsAsyncResp Pointer to object holding response data.
1336 * @param inventoryItems D-Bus inventory items associated with sensors.
1337 * @param ledConnections Connections that provide data for the inventory leds.
1338 * @param callback Callback to invoke when inventory data has been obtained.
1339 * @param ledConnectionsIndex Current index in ledConnections. Only specified
1340 * in recursive calls to this function.
1341 */
1342template <typename Callback>
1343void getInventoryLedData(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001344 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1345 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
1346 const std::shared_ptr<std::map<std::string, std::string>>& ledConnections,
Anthony Wilsond5005492019-07-31 16:34:17 -05001347 Callback&& callback, size_t ledConnectionsIndex = 0)
1348{
Ed Tanous62598e32023-07-17 17:06:25 -07001349 BMCWEB_LOG_DEBUG("getInventoryLedData enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001350
1351 // If no more connections left, call callback
1352 if (ledConnectionsIndex >= ledConnections->size())
1353 {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001354 callback();
Ed Tanous62598e32023-07-17 17:06:25 -07001355 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001356 return;
1357 }
1358
1359 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +00001360 auto it = ledConnections->begin();
1361 std::advance(it, ledConnectionsIndex);
Anthony Wilsond5005492019-07-31 16:34:17 -05001362 if (it != ledConnections->end())
1363 {
1364 const std::string& ledPath = (*it).first;
1365 const std::string& ledConnection = (*it).second;
1366 // Response handler for Get State property
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001367 auto respHandler =
1368 [sensorsAsyncResp, inventoryItems, ledConnections, ledPath,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001369 callback = std::forward<Callback>(callback),
1370 ledConnectionsIndex](const boost::system::error_code& ec,
1371 const std::string& state) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001372 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler enter");
1373 if (ec)
1374 {
1375 BMCWEB_LOG_ERROR(
1376 "getInventoryLedData respHandler DBus error {}", ec);
1377 messages::internalError(sensorsAsyncResp->asyncResp->res);
1378 return;
1379 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001380
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001381 BMCWEB_LOG_DEBUG("Led state: {}", state);
1382 // Find inventory item with this LED object path
1383 InventoryItem* inventoryItem =
1384 findInventoryItemForLed(*inventoryItems, ledPath);
1385 if (inventoryItem != nullptr)
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001386 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001387 // Store LED state in InventoryItem
1388 if (state.ends_with("On"))
1389 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001390 inventoryItem->ledState = sensor_utils::LedState::ON;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001391 }
1392 else if (state.ends_with("Blink"))
1393 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001394 inventoryItem->ledState = sensor_utils::LedState::BLINK;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001395 }
1396 else if (state.ends_with("Off"))
1397 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001398 inventoryItem->ledState = sensor_utils::LedState::OFF;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001399 }
1400 else
1401 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001402 inventoryItem->ledState =
1403 sensor_utils::LedState::UNKNOWN;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001404 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001405 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001406
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001407 // Recurse to get LED data from next connection
1408 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1409 ledConnections, std::move(callback),
1410 ledConnectionsIndex + 1);
Anthony Wilsond5005492019-07-31 16:34:17 -05001411
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001412 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler exit");
1413 };
Anthony Wilsond5005492019-07-31 16:34:17 -05001414
1415 // Get the State property for the current LED
Ed Tanousdeae6a72024-11-11 21:58:57 -08001416 dbus::utility::getProperty<std::string>(
1417 ledConnection, ledPath, "xyz.openbmc_project.Led.Physical", "State",
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001418 std::move(respHandler));
Anthony Wilsond5005492019-07-31 16:34:17 -05001419 }
1420
Ed Tanous62598e32023-07-17 17:06:25 -07001421 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001422}
1423
1424/**
1425 * @brief Gets LED data for LEDs associated with given inventory items.
1426 *
1427 * Gets the D-Bus connections (services) that provide LED data for the LEDs
1428 * associated with the specified inventory items. Then gets the LED data from
1429 * each connection and stores it in the inventory item.
1430 *
1431 * This data is later used to provide sensor property values in the JSON
1432 * response.
1433 *
1434 * Finds the LED data asynchronously. Invokes callback when information has
1435 * been obtained.
1436 *
1437 * The callback must have the following signature:
1438 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001439 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001440 * @endcode
1441 *
1442 * @param sensorsAsyncResp Pointer to object holding response data.
1443 * @param inventoryItems D-Bus inventory items associated with sensors.
1444 * @param callback Callback to invoke when inventory items have been obtained.
1445 */
1446template <typename Callback>
1447void getInventoryLeds(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001448 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1449 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Anthony Wilsond5005492019-07-31 16:34:17 -05001450 Callback&& callback)
1451{
Ed Tanous62598e32023-07-17 17:06:25 -07001452 BMCWEB_LOG_DEBUG("getInventoryLeds enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001453
1454 const std::string path = "/xyz/openbmc_project";
George Liue99073f2022-12-09 11:06:16 +08001455 constexpr std::array<std::string_view, 1> interfaces = {
Anthony Wilsond5005492019-07-31 16:34:17 -05001456 "xyz.openbmc_project.Led.Physical"};
1457
George Liue99073f2022-12-09 11:06:16 +08001458 // Make call to ObjectMapper to find all inventory items
1459 dbus::utility::getSubTree(
1460 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001461 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001462 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001463 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001464 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001465 // Response handler for parsing output from GetSubTree
1466 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler enter");
1467 if (ec)
Anthony Wilsond5005492019-07-31 16:34:17 -05001468 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001469 messages::internalError(sensorsAsyncResp->asyncResp->res);
1470 BMCWEB_LOG_ERROR("getInventoryLeds respHandler DBus error {}",
1471 ec);
1472 return;
Anthony Wilsond5005492019-07-31 16:34:17 -05001473 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001474
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001475 // Build map of LED object paths to connections
1476 std::shared_ptr<std::map<std::string, std::string>> ledConnections =
1477 std::make_shared<std::map<std::string, std::string>>();
1478
1479 // Loop through objects from GetSubTree
1480 for (const std::pair<std::string,
1481 std::vector<std::pair<
1482 std::string, std::vector<std::string>>>>&
1483 object : subtree)
1484 {
1485 // Check if object path is LED for one of the specified
1486 // inventory items
1487 const std::string& ledPath = object.first;
1488 if (findInventoryItemForLed(*inventoryItems, ledPath) !=
1489 nullptr)
1490 {
1491 // Add mapping from ledPath to connection
1492 const std::string& connection =
1493 object.second.begin()->first;
1494 (*ledConnections)[ledPath] = connection;
1495 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", ledPath,
1496 connection);
1497 }
1498 }
1499
1500 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1501 ledConnections, std::move(callback));
1502 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler exit");
1503 });
Ed Tanous62598e32023-07-17 17:06:25 -07001504 BMCWEB_LOG_DEBUG("getInventoryLeds exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001505}
1506
1507/**
Gunnar Mills42cbe532019-08-15 15:26:54 -05001508 * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent
1509 *
1510 * Uses the specified connections (services) (currently assumes just one) to
1511 * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in
1512 * the inventoryItems vector. Only stores data in Power Supply inventoryItems.
1513 *
1514 * This data is later used to provide sensor property values in the JSON
1515 * response.
1516 *
1517 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1518 * when data has been obtained.
1519 *
1520 * The callback must have the following signature:
1521 * @code
1522 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1523 * @endcode
1524 *
1525 * @param sensorsAsyncResp Pointer to object holding response data.
1526 * @param inventoryItems D-Bus inventory items associated with sensors.
1527 * @param psAttributesConnections Connections that provide data for the Power
1528 * Supply Attributes
1529 * @param callback Callback to invoke when data has been obtained.
1530 */
1531template <typename Callback>
1532void getPowerSupplyAttributesData(
Ed Tanousb5a76932020-09-29 16:16:58 -07001533 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Ed Tanousdaadfb22024-12-20 09:25:54 -08001534 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001535 const std::map<std::string, std::string>& psAttributesConnections,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001536 Callback&& callback)
1537{
Ed Tanous62598e32023-07-17 17:06:25 -07001538 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001539
1540 if (psAttributesConnections.empty())
1541 {
Ed Tanous62598e32023-07-17 17:06:25 -07001542 BMCWEB_LOG_DEBUG("Can't find PowerSupplyAttributes, no connections!");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001543 callback(inventoryItems);
1544 return;
1545 }
1546
1547 // Assuming just one connection (service) for now
Nan Zhoufe04d492022-06-22 17:10:41 +00001548 auto it = psAttributesConnections.begin();
Gunnar Mills42cbe532019-08-15 15:26:54 -05001549
1550 const std::string& psAttributesPath = (*it).first;
1551 const std::string& psAttributesConnection = (*it).second;
1552
1553 // Response handler for Get DeratingFactor property
Patrick Williams5a39f772023-10-20 11:20:21 -05001554 auto respHandler = [sensorsAsyncResp, inventoryItems,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001555 callback = std::forward<Callback>(callback)](
Patrick Williams5a39f772023-10-20 11:20:21 -05001556 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001557 uint32_t value) mutable {
Ed Tanous62598e32023-07-17 17:06:25 -07001558 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001559 if (ec)
1560 {
Ed Tanous62598e32023-07-17 17:06:25 -07001561 BMCWEB_LOG_ERROR(
1562 "getPowerSupplyAttributesData respHandler DBus error {}", ec);
zhanghch058d1b46d2021-04-01 11:18:24 +08001563 messages::internalError(sensorsAsyncResp->asyncResp->res);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001564 return;
1565 }
1566
Ed Tanous62598e32023-07-17 17:06:25 -07001567 BMCWEB_LOG_DEBUG("PS EfficiencyPercent value: {}", value);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001568 // Store value in Power Supply Inventory Items
1569 for (InventoryItem& inventoryItem : *inventoryItems)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001570 {
Ed Tanous55f79e62022-01-25 11:26:16 -08001571 if (inventoryItem.isPowerSupply)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001572 {
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001573 inventoryItem.powerSupplyEfficiencyPercent =
1574 static_cast<int>(value);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001575 }
1576 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001577
Ed Tanous62598e32023-07-17 17:06:25 -07001578 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001579 callback(inventoryItems);
1580 };
1581
1582 // Get the DeratingFactor property for the PowerSupplyAttributes
1583 // Currently only property on the interface/only one we care about
Ed Tanousdeae6a72024-11-11 21:58:57 -08001584 dbus::utility::getProperty<uint32_t>(
1585 psAttributesConnection, psAttributesPath,
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001586 "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
1587 std::move(respHandler));
Gunnar Mills42cbe532019-08-15 15:26:54 -05001588
Ed Tanous62598e32023-07-17 17:06:25 -07001589 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001590}
1591
1592/**
1593 * @brief Gets the Power Supply Attributes such as EfficiencyPercent
1594 *
1595 * Gets the D-Bus connection (service) that provides Power Supply Attributes
1596 * data. Then gets the Power Supply Attributes data from the connection
1597 * (currently just assumes 1 connection) and stores the data in the inventory
1598 * item.
1599 *
1600 * This data is later used to provide sensor property values in the JSON
1601 * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish.
1602 *
1603 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1604 * when information has been obtained.
1605 *
1606 * The callback must have the following signature:
1607 * @code
1608 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1609 * @endcode
1610 *
1611 * @param sensorsAsyncResp Pointer to object holding response data.
1612 * @param inventoryItems D-Bus inventory items associated with sensors.
1613 * @param callback Callback to invoke when data has been obtained.
1614 */
1615template <typename Callback>
1616void getPowerSupplyAttributes(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001617 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1618 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001619 Callback&& callback)
1620{
Ed Tanous62598e32023-07-17 17:06:25 -07001621 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001622
1623 // Only need the power supply attributes when the Power Schema
Janet Adkins0c728b42024-08-29 11:09:10 -05001624 if (sensorsAsyncResp->chassisSubNode != sensors::powerNodeStr)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001625 {
Ed Tanous62598e32023-07-17 17:06:25 -07001626 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit since not Power");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001627 callback(inventoryItems);
1628 return;
1629 }
1630
George Liue99073f2022-12-09 11:06:16 +08001631 constexpr std::array<std::string_view, 1> interfaces = {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001632 "xyz.openbmc_project.Control.PowerSupplyAttributes"};
1633
George Liue99073f2022-12-09 11:06:16 +08001634 // Make call to ObjectMapper to find the PowerSupplyAttributes service
1635 dbus::utility::getSubTree(
1636 "/xyz/openbmc_project", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001637 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001638 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001639 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001640 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001641 // Response handler for parsing output from GetSubTree
1642 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler enter");
1643 if (ec)
1644 {
1645 messages::internalError(sensorsAsyncResp->asyncResp->res);
1646 BMCWEB_LOG_ERROR(
1647 "getPowerSupplyAttributes respHandler DBus error {}", ec);
1648 return;
1649 }
1650 if (subtree.empty())
1651 {
1652 BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
1653 callback(inventoryItems);
1654 return;
1655 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001656
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001657 // Currently we only support 1 power supply attribute, use this for
1658 // all the power supplies. Build map of object path to connection.
1659 // Assume just 1 connection and 1 path for now.
1660 std::map<std::string, std::string> psAttributesConnections;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001661
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001662 if (subtree[0].first.empty() || subtree[0].second.empty())
1663 {
1664 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1665 callback(inventoryItems);
1666 return;
1667 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001668
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001669 const std::string& psAttributesPath = subtree[0].first;
1670 const std::string& connection = subtree[0].second.begin()->first;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001671
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001672 if (connection.empty())
1673 {
1674 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1675 callback(inventoryItems);
1676 return;
1677 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001678
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001679 psAttributesConnections[psAttributesPath] = connection;
1680 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", psAttributesPath,
1681 connection);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001682
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001683 getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems,
1684 psAttributesConnections,
1685 std::move(callback));
1686 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler exit");
1687 });
Ed Tanous62598e32023-07-17 17:06:25 -07001688 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001689}
1690
1691/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001692 * @brief Gets inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001693 *
1694 * Finds the inventory items that are associated with the specified sensors.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001695 * Then gets D-Bus data for the inventory items, such as presence and VPD.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001696 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001697 * This data is later used to provide sensor property values in the JSON
1698 * response.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001699 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001700 * Finds the inventory items asynchronously. Invokes callback when the
1701 * inventory items have been obtained.
1702 *
1703 * The callback must have the following signature:
1704 * @code
1705 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1706 * @endcode
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001707 *
1708 * @param sensorsAsyncResp Pointer to object holding response data.
1709 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001710 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001711 * @param callback Callback to invoke when inventory items have been obtained.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001712 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001713template <typename Callback>
Patrick Williams504af5a2025-02-03 14:29:03 -05001714inline void getInventoryItems(
1715 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1716 const std::shared_ptr<std::set<std::string>>& sensorNames,
1717 Callback&& callback)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001718{
Ed Tanous62598e32023-07-17 17:06:25 -07001719 BMCWEB_LOG_DEBUG("getInventoryItems enter");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001720 auto getInventoryItemAssociationsCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -07001721 [sensorsAsyncResp, callback = std::forward<Callback>(callback)](
Ed Tanousdaadfb22024-12-20 09:25:54 -08001722 const std::shared_ptr<std::vector<InventoryItem>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07001723 inventoryItems) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001724 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb enter");
1725 auto getInventoryItemsConnectionsCb =
1726 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001727 callback = std::forward<Callback>(callback)](
Ed Tanousdaadfb22024-12-20 09:25:54 -08001728 const std::shared_ptr<std::set<std::string>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07001729 invConnections) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001730 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb enter");
1731 auto getInventoryItemsDataCb =
1732 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001733 callback =
1734 std::forward<Callback>(callback)]() mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001735 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001736
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001737 auto getInventoryLedsCb =
1738 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001739 callback = std::forward<Callback>(
1740 callback)]() mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001741 BMCWEB_LOG_DEBUG(
1742 "getInventoryLedsCb enter");
1743 // Find Power Supply Attributes and get the
1744 // data
1745 getPowerSupplyAttributes(
1746 sensorsAsyncResp, inventoryItems,
1747 std::move(callback));
1748 BMCWEB_LOG_DEBUG("getInventoryLedsCb exit");
1749 };
1750
1751 // Find led connections and get the data
1752 getInventoryLeds(sensorsAsyncResp, inventoryItems,
1753 std::move(getInventoryLedsCb));
1754 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb exit");
1755 };
1756
1757 // Get inventory item data from connections
1758 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1759 invConnections,
1760 std::move(getInventoryItemsDataCb));
1761 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001762 };
1763
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001764 // Get connections that provide inventory item data
1765 getInventoryItemsConnections(
1766 sensorsAsyncResp, inventoryItems,
1767 std::move(getInventoryItemsConnectionsCb));
1768 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001769 };
1770
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001771 // Get associations from sensors to inventory items
Ed Tanousd0090732022-10-04 17:22:56 -07001772 getInventoryItemAssociations(sensorsAsyncResp, sensorNames,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001773 std::move(getInventoryItemAssociationsCb));
Ed Tanous62598e32023-07-17 17:06:25 -07001774 BMCWEB_LOG_DEBUG("getInventoryItems exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001775}
1776
1777/**
1778 * @brief Returns JSON PowerSupply object for the specified inventory item.
1779 *
1780 * Searches for a JSON PowerSupply object that matches the specified inventory
1781 * item. If one is not found, a new PowerSupply object is added to the JSON
1782 * array.
1783 *
1784 * Multiple sensors are often associated with one power supply inventory item.
1785 * As a result, multiple sensor values are stored in one JSON PowerSupply
1786 * object.
1787 *
1788 * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1789 * @param inventoryItem Inventory item for the power supply.
1790 * @param chassisId Chassis that contains the power supply.
1791 * @return JSON PowerSupply object for the specified inventory item.
1792 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001793inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001794 const InventoryItem& inventoryItem,
1795 const std::string& chassisId)
1796{
Ed Tanous18f8f602023-07-18 10:07:23 -07001797 std::string nameS;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001798 nameS.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001799 std::ranges::replace_copy(inventoryItem.name, nameS.begin(), '_', ' ');
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001800 // Check if matching PowerSupply object already exists in JSON array
1801 for (nlohmann::json& powerSupply : powerSupplyArray)
1802 {
Ed Tanous18f8f602023-07-18 10:07:23 -07001803 nlohmann::json::iterator nameIt = powerSupply.find("Name");
1804 if (nameIt == powerSupply.end())
1805 {
1806 continue;
1807 }
1808 const std::string* name = nameIt->get_ptr<std::string*>();
1809 if (name == nullptr)
1810 {
1811 continue;
1812 }
1813 if (nameS == *name)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001814 {
1815 return powerSupply;
1816 }
1817 }
1818
1819 // Add new PowerSupply object to JSON array
1820 powerSupplyArray.push_back({});
1821 nlohmann::json& powerSupply = powerSupplyArray.back();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001822 boost::urls::url url =
1823 boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
Willy Tueddfc432022-09-26 16:46:38 +00001824 url.set_fragment(("/PowerSupplies"_json_pointer).to_string());
1825 powerSupply["@odata.id"] = std::move(url);
Ed Tanous18f8f602023-07-18 10:07:23 -07001826 std::string escaped;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001827 escaped.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001828 std::ranges::replace_copy(inventoryItem.name, escaped.begin(), '_', ' ');
1829 powerSupply["Name"] = std::move(escaped);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001830 powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1831 powerSupply["Model"] = inventoryItem.model;
1832 powerSupply["PartNumber"] = inventoryItem.partNumber;
1833 powerSupply["SerialNumber"] = inventoryItem.serialNumber;
Janet Adkinsf664fd82025-07-23 14:01:43 -05001834 if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_INDICATORLED)
1835 {
1836 sensor_utils::setLedState(powerSupply, &inventoryItem);
1837 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001838
Gunnar Mills42cbe532019-08-15 15:26:54 -05001839 if (inventoryItem.powerSupplyEfficiencyPercent >= 0)
1840 {
1841 powerSupply["EfficiencyPercent"] =
1842 inventoryItem.powerSupplyEfficiencyPercent;
1843 }
1844
Janet Adkinsc9563602024-08-28 11:37:46 -05001845 powerSupply["Status"]["State"] =
1846 sensor_utils::getState(&inventoryItem, true);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001847 const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1848 powerSupply["Status"]["Health"] = health;
1849
1850 return powerSupply;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001851}
1852
1853/**
Shawn McCarneyde629b62019-03-08 10:42:51 -06001854 * @brief Gets the values of the specified sensors.
1855 *
1856 * Stores the results as JSON in the SensorsAsyncResp.
1857 *
1858 * Gets the sensor values asynchronously. Stores the results later when the
1859 * information has been obtained.
1860 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001861 * The sensorNames set contains all requested sensors for the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001862 *
1863 * To minimize the number of DBus calls, the DBus method
1864 * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1865 * values of all sensors provided by a connection (service).
1866 *
1867 * The connections set contains all the connections that provide sensor values.
1868 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001869 * The InventoryItem vector contains D-Bus inventory items associated with the
1870 * sensors. Inventory item data is needed for some Redfish sensor properties.
1871 *
Shawn McCarneyde629b62019-03-08 10:42:51 -06001872 * @param SensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001873 * @param sensorNames All requested sensors within the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001874 * @param connections Connections that provide sensor values.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001875 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001876 * @param inventoryItems Inventory items associated with the sensors.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001877 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001878inline void getSensorData(
Ed Tanous81ce6092020-12-17 16:54:55 +00001879 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001880 const std::shared_ptr<std::set<std::string>>& sensorNames,
1881 const std::set<std::string>& connections,
Ed Tanousb5a76932020-09-29 16:16:58 -07001882 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001883{
Ed Tanous62598e32023-07-17 17:06:25 -07001884 BMCWEB_LOG_DEBUG("getSensorData enter");
Shawn McCarneyde629b62019-03-08 10:42:51 -06001885 // Get managed objects from all services exposing sensors
1886 for (const std::string& connection : connections)
1887 {
George Liu5eb468d2023-06-20 17:03:24 +08001888 sdbusplus::message::object_path sensorPath(
1889 "/xyz/openbmc_project/sensors");
1890 dbus::utility::getManagedObjects(
1891 connection, sensorPath,
Ed Tanous002d39b2022-05-31 08:59:27 -07001892 [sensorsAsyncResp, sensorNames,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001893 inventoryItems](const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -07001894 const dbus::utility::ManagedObjectType& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001895 BMCWEB_LOG_DEBUG("getManagedObjectsCb enter");
1896 if (ec)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001897 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001898 BMCWEB_LOG_ERROR("getManagedObjectsCb DBUS error: {}", ec);
1899 messages::internalError(sensorsAsyncResp->asyncResp->res);
1900 return;
1901 }
Janet Adkins0c728b42024-08-29 11:09:10 -05001902 auto chassisSubNode = sensor_utils::chassisSubNodeFromString(
1903 sensorsAsyncResp->chassisSubNode);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001904 // Go through all objects and update response with sensor data
1905 for (const auto& objDictEntry : resp)
1906 {
1907 const std::string& objPath =
1908 static_cast<const std::string&>(objDictEntry.first);
1909 BMCWEB_LOG_DEBUG("getManagedObjectsCb parsing object {}",
Ed Tanous62598e32023-07-17 17:06:25 -07001910 objPath);
Shawn McCarneyde629b62019-03-08 10:42:51 -06001911
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001912 std::vector<std::string> split;
1913 // Reserve space for
1914 // /xyz/openbmc_project/sensors/<name>/<subname>
1915 split.reserve(6);
1916 // NOLINTNEXTLINE
1917 bmcweb::split(split, objPath, '/');
1918 if (split.size() < 6)
Nan Zhou928fefb2022-03-28 08:45:00 -07001919 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001920 BMCWEB_LOG_ERROR("Got path that isn't long enough {}",
1921 objPath);
1922 continue;
Nan Zhou928fefb2022-03-28 08:45:00 -07001923 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001924 // These indexes aren't intuitive, as split puts an empty
1925 // string at the beginning
1926 const std::string& sensorType = split[4];
1927 const std::string& sensorName = split[5];
1928 BMCWEB_LOG_DEBUG("sensorName {} sensorType {}", sensorName,
1929 sensorType);
Ed Tanous3d158642025-05-12 14:20:49 -07001930 if (!sensorNames->contains(objPath))
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001931 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001932 BMCWEB_LOG_DEBUG("{} not in sensor list ", sensorName);
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001933 continue;
1934 }
1935
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001936 // Find inventory item (if any) associated with sensor
1937 InventoryItem* inventoryItem =
1938 findInventoryItemForSensor(inventoryItems, objPath);
1939
1940 const std::string& sensorSchema =
1941 sensorsAsyncResp->chassisSubNode;
1942
1943 nlohmann::json* sensorJson = nullptr;
1944
Janet Adkins0c728b42024-08-29 11:09:10 -05001945 if (sensorSchema == sensors::sensorsNodeStr &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001946 !sensorsAsyncResp->efficientExpand)
Nan Zhou928fefb2022-03-28 08:45:00 -07001947 {
Janet Adkins1516c212024-08-14 13:22:41 -05001948 std::string sensorId =
1949 redfish::sensor_utils::getSensorId(sensorName,
1950 sensorType);
Ed Tanous677bb752022-09-15 10:52:19 -07001951
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001952 sensorsAsyncResp->asyncResp->res
1953 .jsonValue["@odata.id"] = boost::urls::format(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001954 "/redfish/v1/Chassis/{}/{}/{}",
Ed Tanous677bb752022-09-15 10:52:19 -07001955 sensorsAsyncResp->chassisId,
1956 sensorsAsyncResp->chassisSubNode, sensorId);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001957 sensorJson =
1958 &(sensorsAsyncResp->asyncResp->res.jsonValue);
Nan Zhou928fefb2022-03-28 08:45:00 -07001959 }
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001960 else
1961 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001962 std::string fieldName;
1963 if (sensorsAsyncResp->efficientExpand)
1964 {
1965 fieldName = "Members";
1966 }
1967 else if (sensorType == "temperature")
1968 {
1969 fieldName = "Temperatures";
1970 }
1971 else if (sensorType == "fan" ||
1972 sensorType == "fan_tach" ||
1973 sensorType == "fan_pwm")
1974 {
1975 fieldName = "Fans";
1976 }
1977 else if (sensorType == "voltage")
1978 {
1979 fieldName = "Voltages";
1980 }
1981 else if (sensorType == "power")
1982 {
1983 if (sensorName == "total_power")
1984 {
1985 fieldName = "PowerControl";
1986 }
1987 else if ((inventoryItem != nullptr) &&
1988 (inventoryItem->isPowerSupply))
1989 {
1990 fieldName = "PowerSupplies";
1991 }
1992 else
1993 {
1994 // Other power sensors are in SensorCollection
1995 continue;
1996 }
1997 }
1998 else
1999 {
2000 BMCWEB_LOG_ERROR(
2001 "Unsure how to handle sensorType {}",
2002 sensorType);
2003 continue;
2004 }
2005
2006 nlohmann::json& tempArray =
2007 sensorsAsyncResp->asyncResp->res
2008 .jsonValue[fieldName];
2009 if (fieldName == "PowerControl")
2010 {
2011 if (tempArray.empty())
2012 {
2013 // Put multiple "sensors" into a single
2014 // PowerControl. Follows MemberId naming and
2015 // naming in power.hpp.
2016 nlohmann::json::object_t power;
2017 boost::urls::url url = boost::urls::format(
2018 "/redfish/v1/Chassis/{}/{}",
2019 sensorsAsyncResp->chassisId,
2020 sensorsAsyncResp->chassisSubNode);
2021 url.set_fragment(
2022 (""_json_pointer / fieldName / "0")
2023 .to_string());
2024 power["@odata.id"] = std::move(url);
2025 tempArray.emplace_back(std::move(power));
2026 }
2027 sensorJson = &(tempArray.back());
2028 }
2029 else if (fieldName == "PowerSupplies")
2030 {
2031 if (inventoryItem != nullptr)
2032 {
2033 sensorJson = &(getPowerSupply(
2034 tempArray, *inventoryItem,
2035 sensorsAsyncResp->chassisId));
2036 }
2037 }
2038 else if (fieldName == "Members")
2039 {
Janet Adkins1516c212024-08-14 13:22:41 -05002040 std::string sensorId =
2041 redfish::sensor_utils::getSensorId(sensorName,
2042 sensorType);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002043
2044 nlohmann::json::object_t member;
2045 member["@odata.id"] = boost::urls::format(
2046 "/redfish/v1/Chassis/{}/{}/{}",
2047 sensorsAsyncResp->chassisId,
2048 sensorsAsyncResp->chassisSubNode, sensorId);
2049 tempArray.emplace_back(std::move(member));
2050 sensorJson = &(tempArray.back());
2051 }
2052 else
2053 {
2054 nlohmann::json::object_t member;
2055 boost::urls::url url = boost::urls::format(
2056 "/redfish/v1/Chassis/{}/{}",
2057 sensorsAsyncResp->chassisId,
2058 sensorsAsyncResp->chassisSubNode);
2059 url.set_fragment(
2060 (""_json_pointer / fieldName).to_string());
2061 member["@odata.id"] = std::move(url);
2062 tempArray.emplace_back(std::move(member));
2063 sensorJson = &(tempArray.back());
2064 }
2065 }
2066
2067 if (sensorJson != nullptr)
2068 {
Janet Adkins0c728b42024-08-29 11:09:10 -05002069 objectInterfacesToJson(
2070 sensorName, sensorType, chassisSubNode,
2071 objDictEntry.second, *sensorJson, inventoryItem);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002072
2073 std::string path = "/xyz/openbmc_project/sensors/";
2074 path += sensorType;
2075 path += "/";
2076 path += sensorName;
2077 sensorsAsyncResp->addMetadata(*sensorJson, path);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002078 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002079 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002080 if (sensorsAsyncResp.use_count() == 1)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002081 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002082 sortJSONResponse(sensorsAsyncResp);
Janet Adkins0c728b42024-08-29 11:09:10 -05002083 if (chassisSubNode ==
2084 sensor_utils::ChassisSubNode::sensorsNode &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002085 sensorsAsyncResp->efficientExpand)
2086 {
2087 sensorsAsyncResp->asyncResp->res
2088 .jsonValue["Members@odata.count"] =
2089 sensorsAsyncResp->asyncResp->res
2090 .jsonValue["Members"]
2091 .size();
2092 }
Janet Adkins0c728b42024-08-29 11:09:10 -05002093 else if (chassisSubNode ==
2094 sensor_utils::ChassisSubNode::thermalNode)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002095 {
2096 populateFanRedundancy(sensorsAsyncResp);
2097 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002098 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002099 BMCWEB_LOG_DEBUG("getManagedObjectsCb exit");
2100 });
Ed Tanous23a21a12020-07-25 04:45:05 +00002101 }
Ed Tanous62598e32023-07-17 17:06:25 -07002102 BMCWEB_LOG_DEBUG("getSensorData exit");
Shawn McCarneyde629b62019-03-08 10:42:51 -06002103}
2104
Patrick Williams504af5a2025-02-03 14:29:03 -05002105inline void processSensorList(
2106 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
2107 const std::shared_ptr<std::set<std::string>>& sensorNames)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002108{
Nan Zhoufe04d492022-06-22 17:10:41 +00002109 auto getConnectionCb = [sensorsAsyncResp, sensorNames](
2110 const std::set<std::string>& connections) {
Ed Tanous62598e32023-07-17 17:06:25 -07002111 BMCWEB_LOG_DEBUG("getConnectionCb enter");
Ed Tanousd0090732022-10-04 17:22:56 -07002112 auto getInventoryItemsCb =
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002113 [sensorsAsyncResp, sensorNames, connections](
2114 const std::shared_ptr<std::vector<InventoryItem>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07002115 inventoryItems) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002116 BMCWEB_LOG_DEBUG("getInventoryItemsCb enter");
2117 // Get sensor data and store results in JSON
2118 getSensorData(sensorsAsyncResp, sensorNames, connections,
2119 inventoryItems);
2120 BMCWEB_LOG_DEBUG("getInventoryItemsCb exit");
2121 };
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002122
Ed Tanousd0090732022-10-04 17:22:56 -07002123 // Get inventory items associated with sensors
2124 getInventoryItems(sensorsAsyncResp, sensorNames,
2125 std::move(getInventoryItemsCb));
2126
Ed Tanous62598e32023-07-17 17:06:25 -07002127 BMCWEB_LOG_DEBUG("getConnectionCb exit");
Ed Tanous002d39b2022-05-31 08:59:27 -07002128 };
2129
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002130 // Get set of connections that provide sensor values
Ed Tanous81ce6092020-12-17 16:54:55 +00002131 getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002132}
2133
Shawn McCarneyde629b62019-03-08 10:42:51 -06002134/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002135 * @brief Entry point for retrieving sensors data related to requested
2136 * chassis.
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02002137 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002138 */
Patrick Williams504af5a2025-02-03 14:29:03 -05002139inline void getChassisData(
2140 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002141{
Ed Tanous62598e32023-07-17 17:06:25 -07002142 BMCWEB_LOG_DEBUG("getChassisData enter");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002143 auto getChassisCb =
Ed Tanous81ce6092020-12-17 16:54:55 +00002144 [sensorsAsyncResp](
Nan Zhoufe04d492022-06-22 17:10:41 +00002145 const std::shared_ptr<std::set<std::string>>& sensorNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002146 BMCWEB_LOG_DEBUG("getChassisCb enter");
2147 processSensorList(sensorsAsyncResp, sensorNames);
2148 BMCWEB_LOG_DEBUG("getChassisCb exit");
2149 };
Nan Zhou928fefb2022-03-28 08:45:00 -07002150 // SensorCollection doesn't contain the Redundancy property
Janet Adkins0c728b42024-08-29 11:09:10 -05002151 if (sensorsAsyncResp->chassisSubNode != sensors::sensorsNodeStr)
Nan Zhou928fefb2022-03-28 08:45:00 -07002152 {
2153 sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
2154 nlohmann::json::array();
2155 }
Shawn McCarney26f03892019-05-03 13:20:24 -05002156 // Get set of sensors in chassis
Ed Tanous7f1cc262022-08-09 13:33:57 -07002157 getChassis(sensorsAsyncResp->asyncResp, sensorsAsyncResp->chassisId,
2158 sensorsAsyncResp->chassisSubNode, sensorsAsyncResp->types,
2159 std::move(getChassisCb));
Ed Tanous62598e32023-07-17 17:06:25 -07002160 BMCWEB_LOG_DEBUG("getChassisData exit");
Ed Tanous271584a2019-07-09 16:24:22 -07002161}
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002162
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302163/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002164 * @brief Find the requested sensorName in the list of all sensors supplied by
2165 * the chassis node
2166 *
2167 * @param sensorName The sensor name supplied in the PATCH request
2168 * @param sensorsList The list of sensors managed by the chassis node
2169 * @param sensorsModified The list of sensors that were found as a result of
2170 * repeated calls to this function
2171 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002172inline bool findSensorNameUsingSensorPath(
2173 std::string_view sensorName, const std::set<std::string>& sensorsList,
2174 std::set<std::string>& sensorsModified)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002175{
Nan Zhoufe04d492022-06-22 17:10:41 +00002176 for (const auto& chassisSensor : sensorsList)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002177 {
George Liu28aa8de2021-02-01 15:13:30 +08002178 sdbusplus::message::object_path path(chassisSensor);
Ed Tanousb00dcc22021-02-23 12:52:50 -08002179 std::string thisSensorName = path.filename();
George Liu28aa8de2021-02-01 15:13:30 +08002180 if (thisSensorName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002181 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002182 continue;
2183 }
2184 if (thisSensorName == sensorName)
2185 {
2186 sensorsModified.emplace(chassisSensor);
2187 return true;
2188 }
2189 }
2190 return false;
2191}
2192
2193/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302194 * @brief Entry point for overriding sensor values of given sensor
2195 *
zhanghch058d1b46d2021-04-01 11:18:24 +08002196 * @param sensorAsyncResp response object
Carol Wang4bb3dc32019-10-17 18:15:02 +08002197 * @param allCollections Collections extract from sensors' request patch info
jayaprakash Mutyala91e130a2020-03-04 22:26:38 +00002198 * @param chassisSubNode Chassis Node for which the query has to happen
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302199 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002200inline void setSensorsOverride(
Ed Tanousb5a76932020-09-29 16:16:58 -07002201 const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
Ed Tanous08850572024-03-06 15:09:17 -08002202 std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>&
jayaprakash Mutyala397fd612020-02-06 23:33:34 +00002203 allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302204{
Ed Tanous62598e32023-07-17 17:06:25 -07002205 BMCWEB_LOG_INFO("setSensorsOverride for subNode{}",
2206 sensorAsyncResp->chassisSubNode);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302207
Ed Tanousd02aad32024-02-13 14:43:34 -08002208 std::string_view propertyValueName;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302209 std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302210 std::string memberId;
Ed Tanous543f4402022-01-06 13:12:53 -08002211 double value = 0.0;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302212 for (auto& collectionItems : allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302213 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302214 if (collectionItems.first == "Temperatures")
2215 {
2216 propertyValueName = "ReadingCelsius";
2217 }
2218 else if (collectionItems.first == "Fans")
2219 {
2220 propertyValueName = "Reading";
2221 }
2222 else
2223 {
2224 propertyValueName = "ReadingVolts";
2225 }
2226 for (auto& item : collectionItems.second)
2227 {
Patrick Williams504af5a2025-02-03 14:29:03 -05002228 if (!json_util::readJsonObject( //
Myung Baeafc474a2024-10-09 00:53:29 -07002229 item, sensorAsyncResp->asyncResp->res, //
Patrick Williams504af5a2025-02-03 14:29:03 -05002230 "MemberId", memberId, //
2231 propertyValueName, value //
Myung Baeafc474a2024-10-09 00:53:29 -07002232 ))
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302233 {
2234 return;
2235 }
2236 overrideMap.emplace(memberId,
2237 std::make_pair(value, collectionItems.first));
2238 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302239 }
Carol Wang4bb3dc32019-10-17 18:15:02 +08002240
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002241 auto getChassisSensorListCb = [sensorAsyncResp, overrideMap,
2242 propertyValueNameStr =
2243 std::string(propertyValueName)](
2244 const std::shared_ptr<
2245 std::set<std::string>>& sensorsList) {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002246 // Match sensor names in the PATCH request to those managed by the
2247 // chassis node
Nan Zhoufe04d492022-06-22 17:10:41 +00002248 const std::shared_ptr<std::set<std::string>> sensorNames =
2249 std::make_shared<std::set<std::string>>();
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302250 for (const auto& item : overrideMap)
2251 {
2252 const auto& sensor = item.first;
Ed Tanousc71d6122022-11-29 14:10:32 -08002253 std::pair<std::string, std::string> sensorNameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002254 redfish::sensor_utils::splitSensorNameAndType(sensor);
Ed Tanousc71d6122022-11-29 14:10:32 -08002255 if (!findSensorNameUsingSensorPath(sensorNameType.second,
2256 *sensorsList, *sensorNames))
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302257 {
Ed Tanous62598e32023-07-17 17:06:25 -07002258 BMCWEB_LOG_INFO("Unable to find memberId {}", item.first);
zhanghch058d1b46d2021-04-01 11:18:24 +08002259 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302260 item.second.second, item.first);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302261 return;
2262 }
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302263 }
2264 // Get the connection to which the memberId belongs
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002265 auto getObjectsWithConnectionCb = [sensorAsyncResp, overrideMap,
2266 propertyValueNameStr](
2267 const std::set<
2268 std::string>& /*connections*/,
2269 const std::set<std::pair<
2270 std::string, std::string>>&
2271 objectsWithConnection) {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002272 if (objectsWithConnection.size() != overrideMap.size())
2273 {
Ed Tanous62598e32023-07-17 17:06:25 -07002274 BMCWEB_LOG_INFO(
2275 "Unable to find all objects with proper connection {} requested {}",
2276 objectsWithConnection.size(), overrideMap.size());
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002277 messages::resourceNotFound(
2278 sensorAsyncResp->asyncResp->res,
Janet Adkins0c728b42024-08-29 11:09:10 -05002279 sensorAsyncResp->chassisSubNode == sensors::thermalNodeStr
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002280 ? "Temperatures"
2281 : "Voltages",
2282 "Count");
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002283 return;
2284 }
2285 for (const auto& item : objectsWithConnection)
2286 {
2287 sdbusplus::message::object_path path(item.first);
2288 std::string sensorName = path.filename();
2289 if (sensorName.empty())
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302290 {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002291 messages::internalError(sensorAsyncResp->asyncResp->res);
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302292 return;
2293 }
Janet Adkins1516c212024-08-14 13:22:41 -05002294 std::string id = redfish::sensor_utils::getSensorId(
2295 sensorName, path.parent_path().filename());
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302296
Ban Feng3f5eb752023-06-29 09:19:20 +08002297 const auto& iterator = overrideMap.find(id);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002298 if (iterator == overrideMap.end())
2299 {
Ed Tanous62598e32023-07-17 17:06:25 -07002300 BMCWEB_LOG_INFO("Unable to find sensor object{}",
2301 item.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002302 messages::internalError(sensorAsyncResp->asyncResp->res);
2303 return;
2304 }
Ginu Georgee93abac2024-06-14 17:35:27 +05302305 setDbusProperty(sensorAsyncResp->asyncResp,
2306 propertyValueNameStr, item.second, item.first,
2307 "xyz.openbmc_project.Sensor.Value", "Value",
Ed Tanousd02aad32024-02-13 14:43:34 -08002308 iterator->second.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002309 }
2310 };
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302311 // Get object with connection for the given sensor name
2312 getObjectsWithConnection(sensorAsyncResp, sensorNames,
2313 std::move(getObjectsWithConnectionCb));
2314 };
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302315 // get full sensor list for the given chassisId and cross verify the sensor.
Ed Tanous7f1cc262022-08-09 13:33:57 -07002316 getChassis(sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId,
2317 sensorAsyncResp->chassisSubNode, sensorAsyncResp->types,
2318 std::move(getChassisSensorListCb));
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302319}
2320
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002321/**
2322 * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus
2323 * path of the sensor.
2324 *
2325 * Function builds valid Redfish response for sensor query of given chassis and
2326 * node. It then builds metadata about Redfish<->D-Bus correlations and provides
2327 * it to caller in a callback.
2328 *
2329 * @param chassis Chassis for which retrieval should be performed
Janet Adkinsc9563602024-08-28 11:37:46 -05002330 * @param node Node (group) of sensors. See sensor_utils::node for supported
2331 * values
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002332 * @param mapComplete Callback to be called with retrieval result
2333 */
Ed Tanous931edc72023-11-01 12:09:07 -07002334template <typename Callback>
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002335inline void retrieveUriToDbusMap(
2336 const std::string& chassis, const std::string& node, Callback&& mapComplete)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002337{
Ed Tanous02da7c52022-02-27 00:09:02 -08002338 decltype(sensors::paths)::const_iterator pathIt =
2339 std::find_if(sensors::paths.cbegin(), sensors::paths.cend(),
2340 [&node](auto&& val) { return val.first == node; });
2341 if (pathIt == sensors::paths.cend())
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002342 {
Ed Tanous62598e32023-07-17 17:06:25 -07002343 BMCWEB_LOG_ERROR("Wrong node provided : {}", node);
Ed Tanous6804b5c2023-10-31 14:50:03 -07002344 std::map<std::string, std::string> noop;
2345 mapComplete(boost::beast::http::status::bad_request, noop);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002346 return;
2347 }
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002348
Nan Zhou72374eb2022-01-27 17:06:51 -08002349 auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002350 auto callback =
2351 [asyncResp, mapCompleteCb = std::forward<Callback>(mapComplete)](
2352 const boost::beast::http::status status,
2353 const std::map<std::string, std::string>& uriToDbus) {
2354 mapCompleteCb(status, uriToDbus);
2355 };
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002356
2357 auto resp = std::make_shared<SensorsAsyncResp>(
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002358 asyncResp, chassis, pathIt->second, node, std::move(callback));
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002359 getChassisData(resp);
2360}
2361
Nan Zhoubacb2162022-04-06 11:28:32 -07002362namespace sensors
2363{
Nan Zhou928fefb2022-03-28 08:45:00 -07002364
Nan Zhoubacb2162022-04-06 11:28:32 -07002365inline void getChassisCallback(
Ed Tanousc1d019a2022-08-06 09:36:06 -07002366 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2367 std::string_view chassisId, std::string_view chassisSubNode,
Nan Zhoufe04d492022-06-22 17:10:41 +00002368 const std::shared_ptr<std::set<std::string>>& sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002369{
Ed Tanous62598e32023-07-17 17:06:25 -07002370 BMCWEB_LOG_DEBUG("getChassisCallback enter ");
Nan Zhoubacb2162022-04-06 11:28:32 -07002371
Ed Tanousc1d019a2022-08-06 09:36:06 -07002372 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
2373 for (const std::string& sensor : *sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002374 {
Ed Tanous62598e32023-07-17 17:06:25 -07002375 BMCWEB_LOG_DEBUG("Adding sensor: {}", sensor);
Nan Zhoubacb2162022-04-06 11:28:32 -07002376
2377 sdbusplus::message::object_path path(sensor);
2378 std::string sensorName = path.filename();
2379 if (sensorName.empty())
2380 {
Ed Tanous62598e32023-07-17 17:06:25 -07002381 BMCWEB_LOG_ERROR("Invalid sensor path: {}", sensor);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002382 messages::internalError(asyncResp->res);
Nan Zhoubacb2162022-04-06 11:28:32 -07002383 return;
2384 }
Ed Tanousc1d019a2022-08-06 09:36:06 -07002385 std::string type = path.parent_path().filename();
Janet Adkins1516c212024-08-14 13:22:41 -05002386 std::string id = redfish::sensor_utils::getSensorId(sensorName, type);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002387
Ed Tanous14766872022-03-15 10:44:42 -07002388 nlohmann::json::object_t member;
Ed Tanousef4c65b2023-04-24 15:28:50 -07002389 member["@odata.id"] = boost::urls::format(
2390 "/redfish/v1/Chassis/{}/{}/{}", chassisId, chassisSubNode, id);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002391
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002392 entriesArray.emplace_back(std::move(member));
Nan Zhoubacb2162022-04-06 11:28:32 -07002393 }
2394
Ed Tanousc1d019a2022-08-06 09:36:06 -07002395 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Ed Tanous62598e32023-07-17 17:06:25 -07002396 BMCWEB_LOG_DEBUG("getChassisCallback exit");
Nan Zhoubacb2162022-04-06 11:28:32 -07002397}
Nan Zhoue6bd8462022-06-01 04:35:35 +00002398
Ed Tanousac106bf2023-06-07 09:24:59 -07002399inline void handleSensorCollectionGet(
2400 App& app, const crow::Request& req,
2401 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2402 const std::string& chassisId)
Nan Zhoude167a62022-06-01 04:47:45 +00002403{
2404 query_param::QueryCapabilities capabilities = {
2405 .canDelegateExpandLevel = 1,
2406 };
2407 query_param::Query delegatedQuery;
Ed Tanousac106bf2023-06-07 09:24:59 -07002408 if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
Nan Zhoude167a62022-06-01 04:47:45 +00002409 delegatedQuery, capabilities))
2410 {
2411 return;
2412 }
2413
2414 if (delegatedQuery.expandType != query_param::ExpandType::None)
2415 {
2416 // we perform efficient expand.
Ed Tanousac106bf2023-06-07 09:24:59 -07002417 auto sensorsAsyncResp = std::make_shared<SensorsAsyncResp>(
2418 asyncResp, chassisId, sensors::dbus::sensorPaths,
Janet Adkins0c728b42024-08-29 11:09:10 -05002419 sensors::sensorsNodeStr,
Nan Zhoude167a62022-06-01 04:47:45 +00002420 /*efficientExpand=*/true);
Ed Tanousac106bf2023-06-07 09:24:59 -07002421 getChassisData(sensorsAsyncResp);
Nan Zhoude167a62022-06-01 04:47:45 +00002422
Ed Tanous62598e32023-07-17 17:06:25 -07002423 BMCWEB_LOG_DEBUG(
2424 "SensorCollection doGet exit via efficient expand handler");
Nan Zhoude167a62022-06-01 04:47:45 +00002425 return;
Ed Tanous0bad3202022-06-02 13:53:59 -07002426 }
Nan Zhoude167a62022-06-01 04:47:45 +00002427
Nan Zhoude167a62022-06-01 04:47:45 +00002428 // We get all sensors as hyperlinkes in the chassis (this
2429 // implies we reply on the default query parameters handler)
Janet Adkins0c728b42024-08-29 11:09:10 -05002430 getChassis(asyncResp, chassisId, sensors::sensorsNodeStr, dbus::sensorPaths,
Ed Tanousac106bf2023-06-07 09:24:59 -07002431 std::bind_front(sensors::getChassisCallback, asyncResp,
Janet Adkins0c728b42024-08-29 11:09:10 -05002432 chassisId, sensors::sensorsNodeStr));
Ed Tanousc1d019a2022-08-06 09:36:06 -07002433}
Ed Tanous7f1cc262022-08-09 13:33:57 -07002434
Patrick Williams504af5a2025-02-03 14:29:03 -05002435inline void getSensorFromDbus(
2436 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2437 const std::string& sensorPath,
2438 const ::dbus::utility::MapperGetObject& mapperResponse)
Ed Tanousc1d019a2022-08-06 09:36:06 -07002439{
2440 if (mapperResponse.size() != 1)
2441 {
2442 messages::internalError(asyncResp->res);
2443 return;
2444 }
2445 const auto& valueIface = *mapperResponse.begin();
2446 const std::string& connectionName = valueIface.first;
Ed Tanous62598e32023-07-17 17:06:25 -07002447 BMCWEB_LOG_DEBUG("Looking up {}", connectionName);
2448 BMCWEB_LOG_DEBUG("Path {}", sensorPath);
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +02002449
Ed Tanousdeae6a72024-11-11 21:58:57 -08002450 ::dbus::utility::getAllProperties(
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +02002451 *crow::connections::systemBus, connectionName, sensorPath, "",
Ed Tanousc1d019a2022-08-06 09:36:06 -07002452 [asyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002453 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002454 const ::dbus::utility::DBusPropertiesMap& valuesDict) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002455 if (ec)
2456 {
2457 messages::internalError(asyncResp->res);
2458 return;
2459 }
2460 sdbusplus::message::object_path path(sensorPath);
2461 std::string name = path.filename();
2462 path = path.parent_path();
2463 std::string type = path.filename();
Janet Adkinsc9563602024-08-28 11:37:46 -05002464 sensor_utils::objectPropertiesToJson(
Janet Adkins0c728b42024-08-29 11:09:10 -05002465 name, type, sensor_utils::ChassisSubNode::sensorsNode,
2466 valuesDict, asyncResp->res.jsonValue, nullptr);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002467 });
Nan Zhoude167a62022-06-01 04:47:45 +00002468}
2469
Nan Zhoue6bd8462022-06-01 04:35:35 +00002470inline void handleSensorGet(App& app, const crow::Request& req,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002471 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous677bb752022-09-15 10:52:19 -07002472 const std::string& chassisId,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002473 const std::string& sensorId)
Nan Zhoue6bd8462022-06-01 04:35:35 +00002474{
Ed Tanousc1d019a2022-08-06 09:36:06 -07002475 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Nan Zhoue6bd8462022-06-01 04:35:35 +00002476 {
2477 return;
2478 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002479 std::pair<std::string, std::string> nameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002480 redfish::sensor_utils::splitSensorNameAndType(sensorId);
Ed Tanousc71d6122022-11-29 14:10:32 -08002481 if (nameType.first.empty() || nameType.second.empty())
Ed Tanousc1d019a2022-08-06 09:36:06 -07002482 {
2483 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2484 return;
2485 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002486
Ed Tanousef4c65b2023-04-24 15:28:50 -07002487 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2488 "/redfish/v1/Chassis/{}/Sensors/{}", chassisId, sensorId);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002489
Ed Tanous62598e32023-07-17 17:06:25 -07002490 BMCWEB_LOG_DEBUG("Sensor doGet enter");
Nan Zhoue6bd8462022-06-01 04:35:35 +00002491
George Liu2b731192023-01-11 16:27:13 +08002492 constexpr std::array<std::string_view, 1> interfaces = {
Nan Zhoue6bd8462022-06-01 04:35:35 +00002493 "xyz.openbmc_project.Sensor.Value"};
Ed Tanousc71d6122022-11-29 14:10:32 -08002494 std::string sensorPath = "/xyz/openbmc_project/sensors/" + nameType.first +
2495 '/' + nameType.second;
Nan Zhoue6bd8462022-06-01 04:35:35 +00002496 // Get a list of all of the sensors that implement Sensor.Value
2497 // and get the path and service name associated with the sensor
George Liu2b731192023-01-11 16:27:13 +08002498 ::dbus::utility::getDbusObject(
2499 sensorPath, interfaces,
Myung Baeaec0ec32023-05-31 15:10:01 -05002500 [asyncResp, sensorId,
George Liu2b731192023-01-11 16:27:13 +08002501 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002502 const ::dbus::utility::MapperGetObject& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002503 BMCWEB_LOG_DEBUG("respHandler1 enter");
2504 if (ec == boost::system::errc::io_error)
2505 {
2506 BMCWEB_LOG_WARNING("Sensor not found from getSensorPaths");
2507 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2508 return;
2509 }
2510 if (ec)
2511 {
2512 messages::internalError(asyncResp->res);
2513 BMCWEB_LOG_ERROR(
2514 "Sensor getSensorPaths resp_handler: Dbus error {}", ec);
2515 return;
2516 }
2517 getSensorFromDbus(asyncResp, sensorPath, subtree);
2518 BMCWEB_LOG_DEBUG("respHandler1 exit");
2519 });
Nan Zhoue6bd8462022-06-01 04:35:35 +00002520}
2521
Nan Zhoubacb2162022-04-06 11:28:32 -07002522} // namespace sensors
2523
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002524inline void requestRoutesSensorCollection(App& app)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002525{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002526 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
Ed Tanoused398212021-06-09 17:05:54 -07002527 .privileges(redfish::privileges::getSensorCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002528 .methods(boost::beast::http::verb::get)(
Nan Zhoude167a62022-06-01 04:47:45 +00002529 std::bind_front(sensors::handleSensorCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002530}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002531
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002532inline void requestRoutesSensor(App& app)
2533{
2534 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002535 .privileges(redfish::privileges::getSensor)
Ed Tanous002d39b2022-05-31 08:59:27 -07002536 .methods(boost::beast::http::verb::get)(
Nan Zhoue6bd8462022-06-01 04:35:35 +00002537 std::bind_front(sensors::handleSensorGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002538}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002539
Ed Tanous1abe55e2018-09-05 08:30:59 -07002540} // namespace redfish