blob: d8aa5594b006fe888fe62754b04e99ee5f3c53d1 [file] [log] [blame]
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01001/*
Ed Tanous6be832e2024-09-10 11:44:48 -07002Copyright (c) 2018 Intel Corporation
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010015*/
16#pragma once
17
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080018#include "app.hpp"
19#include "dbus_singleton.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080020#include "dbus_utility.hpp"
Ed Tanous539d8c62024-06-19 14:38:27 -070021#include "generated/enums/redundancy.hpp"
Matt Simmeringaaf08ac2023-10-04 08:41:01 -070022#include "generated/enums/resource.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080023#include "query.hpp"
24#include "registries/privilege_registry.hpp"
Ed Tanous50ebd4a2023-01-19 19:03:17 -080025#include "str_utility.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080026#include "utils/dbus_utils.hpp"
27#include "utils/json_utils.hpp"
28#include "utils/query_param.hpp"
Janet Adkins1516c212024-08-14 13:22:41 -050029#include "utils/sensor_utils.hpp"
Ed Tanous0ec8b832022-03-14 14:56:47 -070030
George Liue99073f2022-12-09 11:06:16 +080031#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070032#include <boost/url/format.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070033#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +020034#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050035
George Liu7a1dbc42022-12-07 16:03:22 +080036#include <array>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050037#include <cmath>
Nan Zhoufe04d492022-06-22 17:10:41 +000038#include <iterator>
Ed Tanous283860f2022-08-29 14:08:50 -070039#include <limits>
Nan Zhoufe04d492022-06-22 17:10:41 +000040#include <map>
Ed Tanous3544d2a2023-08-06 18:12:20 -070041#include <ranges>
Nan Zhoufe04d492022-06-22 17:10:41 +000042#include <set>
Ed Tanous18f8f602023-07-18 10:07:23 -070043#include <string>
George Liu7a1dbc42022-12-07 16:03:22 +080044#include <string_view>
Ed Tanousb5a76932020-09-29 16:16:58 -070045#include <utility>
Ed Tanousabf2add2019-01-22 16:40:12 -080046#include <variant>
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010047
Ed Tanous1abe55e2018-09-05 08:30:59 -070048namespace redfish
49{
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010050
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020051namespace sensors
52{
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020053
Ed Tanous02da7c52022-02-27 00:09:02 -080054// clang-format off
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020055namespace dbus
56{
Ed Tanouscf9e4172022-12-21 09:30:16 -080057constexpr auto powerPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080058 "/xyz/openbmc_project/sensors/voltage",
59 "/xyz/openbmc_project/sensors/power"
60});
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000061
Ed Tanous25b54db2024-04-17 15:40:31 -070062constexpr auto getSensorPaths(){
63 if constexpr(BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM){
64 return std::to_array<std::string_view>({
65 "/xyz/openbmc_project/sensors/power",
66 "/xyz/openbmc_project/sensors/current",
67 "/xyz/openbmc_project/sensors/airflow",
68 "/xyz/openbmc_project/sensors/humidity",
69 "/xyz/openbmc_project/sensors/voltage",
70 "/xyz/openbmc_project/sensors/fan_tach",
71 "/xyz/openbmc_project/sensors/temperature",
72 "/xyz/openbmc_project/sensors/fan_pwm",
73 "/xyz/openbmc_project/sensors/altitude",
74 "/xyz/openbmc_project/sensors/energy",
75 "/xyz/openbmc_project/sensors/utilization"});
76 } else {
77 return std::to_array<std::string_view>({"/xyz/openbmc_project/sensors/power",
78 "/xyz/openbmc_project/sensors/current",
79 "/xyz/openbmc_project/sensors/airflow",
80 "/xyz/openbmc_project/sensors/humidity",
81 "/xyz/openbmc_project/sensors/utilization"});
82}
83}
84
85constexpr auto sensorPaths = getSensorPaths();
Ed Tanous02da7c52022-02-27 00:09:02 -080086
Ed Tanouscf9e4172022-12-21 09:30:16 -080087constexpr auto thermalPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080088 "/xyz/openbmc_project/sensors/fan_tach",
89 "/xyz/openbmc_project/sensors/temperature",
90 "/xyz/openbmc_project/sensors/fan_pwm"
91});
92
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000093} // namespace dbus
Ed Tanous02da7c52022-02-27 00:09:02 -080094// clang-format on
95
Janet Adkins0c728b42024-08-29 11:09:10 -050096constexpr std::string_view powerNodeStr = sensor_utils::chassisSubNodeToString(
97 sensor_utils::ChassisSubNode::powerNode);
98constexpr std::string_view sensorsNodeStr =
99 sensor_utils::chassisSubNodeToString(
100 sensor_utils::ChassisSubNode::sensorsNode);
101constexpr std::string_view thermalNodeStr =
102 sensor_utils::chassisSubNodeToString(
103 sensor_utils::ChassisSubNode::thermalNode);
104
Ed Tanouscf9e4172022-12-21 09:30:16 -0800105using sensorPair =
106 std::pair<std::string_view, std::span<const std::string_view>>;
Ed Tanous02da7c52022-02-27 00:09:02 -0800107static constexpr std::array<sensorPair, 3> paths = {
Janet Adkins0c728b42024-08-29 11:09:10 -0500108 {{sensors::powerNodeStr, dbus::powerPaths},
109 {sensors::sensorsNodeStr, dbus::sensorPaths},
110 {sensors::thermalNodeStr, dbus::thermalPaths}}};
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000111
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200112} // namespace sensors
113
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100114/**
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200115 * SensorsAsyncResp
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100116 * Gathers data needed for response processing after async calls are done
117 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700118class SensorsAsyncResp
119{
120 public:
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200121 using DataCompleteCb = std::function<void(
122 const boost::beast::http::status status,
Nan Zhoufe04d492022-06-22 17:10:41 +0000123 const std::map<std::string, std::string>& uriToDbus)>;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200124
125 struct SensorData
126 {
Ed Tanousf836c1d2024-09-06 16:05:11 -0700127 std::string name;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200128 std::string uri;
Ed Tanousf836c1d2024-09-06 16:05:11 -0700129 std::string dbusPath;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200130 };
131
Ed Tanous8a592812022-06-04 09:06:59 -0700132 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800133 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800134 std::span<const std::string_view> typesIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800135 std::string_view subNode) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400136 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
137 chassisSubNode(subNode), efficientExpand(false)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500138 {}
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200139
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200140 // Store extra data about sensor mapping and return it in callback
Ed Tanous8a592812022-06-04 09:06:59 -0700141 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800142 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800143 std::span<const std::string_view> typesIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800144 std::string_view subNode,
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200145 DataCompleteCb&& creationComplete) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400146 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
147 chassisSubNode(subNode), efficientExpand(false),
148 metadata{std::vector<SensorData>()},
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200149 dataComplete{std::move(creationComplete)}
150 {}
151
Nan Zhou928fefb2022-03-28 08:45:00 -0700152 // sensor collections expand
Ed Tanous8a592812022-06-04 09:06:59 -0700153 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
Nan Zhou928fefb2022-03-28 08:45:00 -0700154 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800155 std::span<const std::string_view> typesIn,
Ed Tanous8a592812022-06-04 09:06:59 -0700156 const std::string_view& subNode, bool efficientExpandIn) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400157 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
158 chassisSubNode(subNode), efficientExpand(efficientExpandIn)
Nan Zhou928fefb2022-03-28 08:45:00 -0700159 {}
160
Ed Tanous1abe55e2018-09-05 08:30:59 -0700161 ~SensorsAsyncResp()
162 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800163 if (asyncResp->res.result() ==
164 boost::beast::http::status::internal_server_error)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700165 {
166 // Reset the json object to clear out any data that made it in
167 // before the error happened todo(ed) handle error condition with
168 // proper code
zhanghch058d1b46d2021-04-01 11:18:24 +0800169 asyncResp->res.jsonValue = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700170 }
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200171
172 if (dataComplete && metadata)
173 {
Nan Zhoufe04d492022-06-22 17:10:41 +0000174 std::map<std::string, std::string> map;
zhanghch058d1b46d2021-04-01 11:18:24 +0800175 if (asyncResp->res.result() == boost::beast::http::status::ok)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200176 {
177 for (auto& sensor : *metadata)
178 {
Ed Tanousc1d019a2022-08-06 09:36:06 -0700179 map.emplace(sensor.uri, sensor.dbusPath);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200180 }
181 }
zhanghch058d1b46d2021-04-01 11:18:24 +0800182 dataComplete(asyncResp->res.result(), map);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200183 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700184 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100185
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800186 SensorsAsyncResp(const SensorsAsyncResp&) = delete;
187 SensorsAsyncResp(SensorsAsyncResp&&) = delete;
188 SensorsAsyncResp& operator=(const SensorsAsyncResp&) = delete;
189 SensorsAsyncResp& operator=(SensorsAsyncResp&&) = delete;
190
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200191 void addMetadata(const nlohmann::json& sensorObject,
Ed Tanousc1d019a2022-08-06 09:36:06 -0700192 const std::string& dbusPath)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200193 {
194 if (metadata)
195 {
Ed Tanousc1d019a2022-08-06 09:36:06 -0700196 metadata->emplace_back(SensorData{
197 sensorObject["Name"], sensorObject["@odata.id"], dbusPath});
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200198 }
199 }
200
201 void updateUri(const std::string& name, const std::string& uri)
202 {
203 if (metadata)
204 {
205 for (auto& sensor : *metadata)
206 {
207 if (sensor.name == name)
208 {
209 sensor.uri = uri;
210 }
211 }
212 }
213 }
214
zhanghch058d1b46d2021-04-01 11:18:24 +0800215 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200216 const std::string chassisId;
Ed Tanouscf9e4172022-12-21 09:30:16 -0800217 const std::span<const std::string_view> types;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200218 const std::string chassisSubNode;
Nan Zhou928fefb2022-03-28 08:45:00 -0700219 const bool efficientExpand;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200220
221 private:
222 std::optional<std::vector<SensorData>> metadata;
223 DataCompleteCb dataComplete;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100224};
225
Janet Adkinsc9563602024-08-28 11:37:46 -0500226using InventoryItem = sensor_utils::InventoryItem;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500227
228/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530229 * @brief Get objects with connection necessary for sensors
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200230 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100231 * @param sensorNames Sensors retrieved from chassis
232 * @param callback Callback for processing gathered connections
233 */
234template <typename Callback>
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530235void getObjectsWithConnection(
Ed Tanous81ce6092020-12-17 16:54:55 +0000236 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +0000237 const std::shared_ptr<std::set<std::string>>& sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530238 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700239{
Ed Tanous62598e32023-07-17 17:06:25 -0700240 BMCWEB_LOG_DEBUG("getObjectsWithConnection enter");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700241 const std::string path = "/xyz/openbmc_project/sensors";
George Liue99073f2022-12-09 11:06:16 +0800242 constexpr std::array<std::string_view, 1> interfaces = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700243 "xyz.openbmc_project.Sensor.Value"};
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100244
George Liue99073f2022-12-09 11:06:16 +0800245 // Make call to ObjectMapper to find all sensors objects
246 dbus::utility::getSubTree(
247 path, 2, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700248 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
George Liue99073f2022-12-09 11:06:16 +0800249 sensorNames](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700250 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400251 // Response handler for parsing objects subtree
252 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler enter");
253 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700254 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400255 messages::internalError(sensorsAsyncResp->asyncResp->res);
256 BMCWEB_LOG_ERROR(
257 "getObjectsWithConnection resp_handler: Dbus error {}", ec);
258 return;
259 }
260
261 BMCWEB_LOG_DEBUG("Found {} subtrees", subtree.size());
262
263 // Make unique list of connections only for requested sensor types
264 // and found in the chassis
265 std::set<std::string> connections;
266 std::set<std::pair<std::string, std::string>> objectsWithConnection;
267
268 BMCWEB_LOG_DEBUG("sensorNames list count: {}", sensorNames->size());
269 for (const std::string& tsensor : *sensorNames)
270 {
271 BMCWEB_LOG_DEBUG("Sensor to find: {}", tsensor);
272 }
273
274 for (const std::pair<std::string,
275 std::vector<std::pair<
276 std::string, std::vector<std::string>>>>&
277 object : subtree)
278 {
279 if (sensorNames->find(object.first) != sensorNames->end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700280 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400281 for (const std::pair<std::string, std::vector<std::string>>&
282 objData : object.second)
283 {
284 BMCWEB_LOG_DEBUG("Adding connection: {}",
285 objData.first);
286 connections.insert(objData.first);
287 objectsWithConnection.insert(
288 std::make_pair(object.first, objData.first));
289 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700290 }
291 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400292 BMCWEB_LOG_DEBUG("Found {} connections", connections.size());
293 callback(std::move(connections), std::move(objectsWithConnection));
294 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler exit");
295 });
Ed Tanous62598e32023-07-17 17:06:25 -0700296 BMCWEB_LOG_DEBUG("getObjectsWithConnection exit");
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530297}
298
299/**
300 * @brief Create connections necessary for sensors
301 * @param SensorsAsyncResp Pointer to object holding response data
302 * @param sensorNames Sensors retrieved from chassis
303 * @param callback Callback for processing gathered connections
304 */
305template <typename Callback>
Ed Tanousdaadfb22024-12-20 09:25:54 -0800306void getConnections(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
307 const std::shared_ptr<std::set<std::string>>& sensorNames,
Nan Zhoufe04d492022-06-22 17:10:41 +0000308 Callback&& callback)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530309{
310 auto objectsWithConnectionCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -0700311 [callback = std::forward<Callback>(callback)](
312 const std::set<std::string>& connections,
313 const std::set<std::pair<std::string, std::string>>&
314 /*objectsWithConnection*/) { callback(connections); };
Ed Tanous81ce6092020-12-17 16:54:55 +0000315 getObjectsWithConnection(sensorsAsyncResp, sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530316 std::move(objectsWithConnectionCb));
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100317}
318
319/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700320 * @brief Shrinks the list of sensors for processing
321 * @param SensorsAysncResp The class holding the Redfish response
322 * @param allSensors A list of all the sensors associated to the
323 * chassis element (i.e. baseboard, front panel, etc...)
324 * @param activeSensors A list that is a reduction of the incoming
325 * allSensors list. Eliminate Thermal sensors when a Power request is
326 * made, and eliminate Power sensors when a Thermal request is made.
327 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000328inline void reduceSensorList(
Ed Tanous7f1cc262022-08-09 13:33:57 -0700329 crow::Response& res, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800330 std::span<const std::string_view> sensorTypes,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700331 const std::vector<std::string>* allSensors,
Nan Zhoufe04d492022-06-22 17:10:41 +0000332 const std::shared_ptr<std::set<std::string>>& activeSensors)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700333{
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700334 if ((allSensors == nullptr) || (activeSensors == nullptr))
335 {
Ed Tanous7f1cc262022-08-09 13:33:57 -0700336 messages::resourceNotFound(res, chassisSubNode,
Janet Adkins0c728b42024-08-29 11:09:10 -0500337 chassisSubNode == sensors::thermalNodeStr
Ed Tanous7f1cc262022-08-09 13:33:57 -0700338 ? "Temperatures"
339 : "Voltages");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700340
341 return;
342 }
343 if (allSensors->empty())
344 {
345 // Nothing to do, the activeSensors object is also empty
346 return;
347 }
348
Ed Tanous7f1cc262022-08-09 13:33:57 -0700349 for (std::string_view type : sensorTypes)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700350 {
351 for (const std::string& sensor : *allSensors)
352 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700353 if (sensor.starts_with(type))
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700354 {
355 activeSensors->emplace(sensor);
356 }
357 }
358 }
359}
360
Ed Tanous7f1cc262022-08-09 13:33:57 -0700361/*
362 *Populates the top level collection for a given subnode. Populates
363 *SensorCollection, Power, or Thermal schemas.
364 *
365 * */
366inline void populateChassisNode(nlohmann::json& jsonValue,
367 std::string_view chassisSubNode)
368{
Janet Adkins0c728b42024-08-29 11:09:10 -0500369 if (chassisSubNode == sensors::powerNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700370 {
371 jsonValue["@odata.type"] = "#Power.v1_5_2.Power";
372 }
Janet Adkins0c728b42024-08-29 11:09:10 -0500373 else if (chassisSubNode == sensors::thermalNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700374 {
375 jsonValue["@odata.type"] = "#Thermal.v1_4_0.Thermal";
376 jsonValue["Fans"] = nlohmann::json::array();
377 jsonValue["Temperatures"] = nlohmann::json::array();
378 }
Janet Adkins0c728b42024-08-29 11:09:10 -0500379 else if (chassisSubNode == sensors::sensorsNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700380 {
381 jsonValue["@odata.type"] = "#SensorCollection.SensorCollection";
382 jsonValue["Description"] = "Collection of Sensors for this Chassis";
383 jsonValue["Members"] = nlohmann::json::array();
384 jsonValue["Members@odata.count"] = 0;
385 }
386
Janet Adkins0c728b42024-08-29 11:09:10 -0500387 if (chassisSubNode != sensors::sensorsNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700388 {
389 jsonValue["Id"] = chassisSubNode;
390 }
391 jsonValue["Name"] = chassisSubNode;
392}
393
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700394/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100395 * @brief Retrieves requested chassis sensors and redundancy data from DBus .
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200396 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100397 * @param callback Callback for next step in gathered sensor processing
398 */
399template <typename Callback>
Ed Tanous7f1cc262022-08-09 13:33:57 -0700400void getChassis(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
401 std::string_view chassisId, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800402 std::span<const std::string_view> sensorTypes,
403 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700404{
Ed Tanous62598e32023-07-17 17:06:25 -0700405 BMCWEB_LOG_DEBUG("getChassis enter");
George Liu7a1dbc42022-12-07 16:03:22 +0800406 constexpr std::array<std::string_view, 2> interfaces = {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700407 "xyz.openbmc_project.Inventory.Item.Board",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500408 "xyz.openbmc_project.Inventory.Item.Chassis"};
George Liu7a1dbc42022-12-07 16:03:22 +0800409
410 // Get the Chassis Collection
411 dbus::utility::getSubTreePaths(
412 "/xyz/openbmc_project/inventory", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700413 [callback = std::forward<Callback>(callback), asyncResp,
Ed Tanous7f1cc262022-08-09 13:33:57 -0700414 chassisIdStr{std::string(chassisId)},
Ed Tanous4e0d8782024-09-06 15:16:41 -0700415 chassisSubNode{std::string(chassisSubNode)},
416 sensorTypes](const boost::system::error_code& ec,
417 const dbus::utility::MapperGetSubTreePathsResponse&
418 chassisPaths) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400419 BMCWEB_LOG_DEBUG("getChassis respHandler enter");
420 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700421 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400422 BMCWEB_LOG_ERROR("getChassis respHandler DBUS error: {}", ec);
423 messages::internalError(asyncResp->res);
424 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700425 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400426 const std::string* chassisPath = nullptr;
427 for (const std::string& chassis : chassisPaths)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700428 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400429 sdbusplus::message::object_path path(chassis);
430 std::string chassisName = path.filename();
431 if (chassisName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700432 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400433 BMCWEB_LOG_ERROR("Failed to find '/' in {}", chassis);
434 continue;
435 }
436 if (chassisName == chassisIdStr)
437 {
438 chassisPath = &chassis;
439 break;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700440 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700441 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400442 if (chassisPath == nullptr)
443 {
444 messages::resourceNotFound(asyncResp->res, "Chassis",
445 chassisIdStr);
446 return;
447 }
448 populateChassisNode(asyncResp->res.jsonValue, chassisSubNode);
449
450 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
451 "/redfish/v1/Chassis/{}/{}", chassisIdStr, chassisSubNode);
452
453 // Get the list of all sensors for this Chassis element
454 std::string sensorPath = *chassisPath + "/all_sensors";
455 dbus::utility::getAssociationEndPoints(
Ed Tanous4e0d8782024-09-06 15:16:41 -0700456 sensorPath, [asyncResp, chassisSubNode, sensorTypes,
457 callback = std::forward<Callback>(callback)](
458 const boost::system::error_code& ec2,
459 const dbus::utility::MapperEndPoints&
460 nodeSensorList) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400461 if (ec2)
462 {
463 if (ec2.value() != EBADR)
464 {
465 messages::internalError(asyncResp->res);
466 return;
467 }
468 }
469 const std::shared_ptr<std::set<std::string>>
470 culledSensorList =
471 std::make_shared<std::set<std::string>>();
472 reduceSensorList(asyncResp->res, chassisSubNode,
473 sensorTypes, &nodeSensorList,
474 culledSensorList);
475 BMCWEB_LOG_DEBUG("Finishing with {}",
476 culledSensorList->size());
477 callback(culledSensorList);
478 });
George Liu7a1dbc42022-12-07 16:03:22 +0800479 });
Ed Tanous62598e32023-07-17 17:06:25 -0700480 BMCWEB_LOG_DEBUG("getChassis exit");
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100481}
482
483/**
Ed Tanous1d7c0052022-08-09 12:32:26 -0700484 * @brief Builds a json sensor representation of a sensor.
485 * @param sensorName The name of the sensor to be built
486 * @param sensorType The type (temperature, fan_tach, etc) of the sensor to
487 * build
Ed Tanous8ece0e42024-01-02 13:16:50 -0800488 * @param chassisSubNode The subnode (thermal, sensor, etc) of the sensor
Ed Tanous1d7c0052022-08-09 12:32:26 -0700489 * @param interfacesDict A dictionary of the interfaces and properties of said
490 * interfaces to be built from
491 * @param sensorJson The json object to fill
492 * @param inventoryItem D-Bus inventory item associated with the sensor. Will
493 * be nullptr if no associated inventory item was found.
494 */
495inline void objectInterfacesToJson(
496 const std::string& sensorName, const std::string& sensorType,
Janet Adkins0c728b42024-08-29 11:09:10 -0500497 const sensor_utils::ChassisSubNode chassisSubNode,
Michael Shen80f79a42023-08-24 13:41:53 +0000498 const dbus::utility::DBusInterfacesMap& interfacesDict,
Ed Tanous1d7c0052022-08-09 12:32:26 -0700499 nlohmann::json& sensorJson, InventoryItem* inventoryItem)
500{
Ed Tanous1d7c0052022-08-09 12:32:26 -0700501 for (const auto& [interface, valuesDict] : interfacesDict)
502 {
Janet Adkinsc9563602024-08-28 11:37:46 -0500503 sensor_utils::objectPropertiesToJson(
504 sensorName, sensorType, chassisSubNode, valuesDict, sensorJson,
505 inventoryItem);
Ed Tanous1d7c0052022-08-09 12:32:26 -0700506 }
Ed Tanous62598e32023-07-17 17:06:25 -0700507 BMCWEB_LOG_DEBUG("Added sensor {}", sensorName);
Ed Tanous1d7c0052022-08-09 12:32:26 -0700508}
509
Ed Tanousb5a76932020-09-29 16:16:58 -0700510inline void populateFanRedundancy(
511 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
James Feist8bd25cc2019-03-15 15:14:00 -0700512{
George Liue99073f2022-12-09 11:06:16 +0800513 constexpr std::array<std::string_view, 1> interfaces = {
514 "xyz.openbmc_project.Control.FanRedundancy"};
515 dbus::utility::getSubTree(
516 "/xyz/openbmc_project/control", 2, interfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800517 [sensorsAsyncResp](
George Liue99073f2022-12-09 11:06:16 +0800518 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800519 const dbus::utility::MapperGetSubTreeResponse& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400520 if (ec)
James Feist8bd25cc2019-03-15 15:14:00 -0700521 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400522 return; // don't have to have this interface
James Feist8bd25cc2019-03-15 15:14:00 -0700523 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400524 for (const std::pair<std::string, dbus::utility::MapperServiceMap>&
525 pathPair : resp)
526 {
527 const std::string& path = pathPair.first;
528 const dbus::utility::MapperServiceMap& objDict =
529 pathPair.second;
530 if (objDict.empty())
James Feist8bd25cc2019-03-15 15:14:00 -0700531 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400532 continue; // this should be impossible
James Feist8bd25cc2019-03-15 15:14:00 -0700533 }
534
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400535 const std::string& owner = objDict.begin()->first;
536 dbus::utility::getAssociationEndPoints(
537 path + "/chassis",
538 [path, owner, sensorsAsyncResp](
539 const boost::system::error_code& ec2,
540 const dbus::utility::MapperEndPoints& endpoints) {
541 if (ec2)
James Feist8bd25cc2019-03-15 15:14:00 -0700542 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400543 return; // if they don't have an association we
544 // can't tell what chassis is
James Feist8bd25cc2019-03-15 15:14:00 -0700545 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400546 auto found = std::ranges::find_if(
547 endpoints,
548 [sensorsAsyncResp](const std::string& entry) {
549 return entry.find(
550 sensorsAsyncResp->chassisId) !=
551 std::string::npos;
552 });
553
554 if (found == endpoints.end())
James Feist8bd25cc2019-03-15 15:14:00 -0700555 {
556 return;
557 }
Ed Tanousdeae6a72024-11-11 21:58:57 -0800558 dbus::utility::getAllProperties(
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400559 *crow::connections::systemBus, owner, path,
560 "xyz.openbmc_project.Control.FanRedundancy",
561 [path, sensorsAsyncResp](
562 const boost::system::error_code& ec3,
563 const dbus::utility::DBusPropertiesMap& ret) {
564 if (ec3)
565 {
566 return; // don't have to have this
567 // interface
568 }
James Feist8bd25cc2019-03-15 15:14:00 -0700569
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400570 const uint8_t* allowedFailures = nullptr;
571 const std::vector<std::string>* collection =
572 nullptr;
573 const std::string* status = nullptr;
James Feist8bd25cc2019-03-15 15:14:00 -0700574
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400575 const bool success =
576 sdbusplus::unpackPropertiesNoThrow(
577 dbus_utils::UnpackErrorPrinter(), ret,
578 "AllowedFailures", allowedFailures,
579 "Collection", collection, "Status",
580 status);
James Feist8bd25cc2019-03-15 15:14:00 -0700581
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400582 if (!success)
583 {
584 messages::internalError(
585 sensorsAsyncResp->asyncResp->res);
586 return;
587 }
588
589 if (allowedFailures == nullptr ||
590 collection == nullptr || status == nullptr)
591 {
592 BMCWEB_LOG_ERROR(
593 "Invalid redundancy interface");
594 messages::internalError(
595 sensorsAsyncResp->asyncResp->res);
596 return;
597 }
598
599 sdbusplus::message::object_path objectPath(
600 path);
601 std::string name = objectPath.filename();
602 if (name.empty())
603 {
604 // this should be impossible
605 messages::internalError(
606 sensorsAsyncResp->asyncResp->res);
607 return;
608 }
609 std::ranges::replace(name, '_', ' ');
610
611 std::string health;
612
613 if (status->ends_with("Full"))
614 {
615 health = "OK";
616 }
617 else if (status->ends_with("Degraded"))
618 {
619 health = "Warning";
620 }
621 else
622 {
623 health = "Critical";
624 }
625 nlohmann::json::array_t redfishCollection;
626 const auto& fanRedfish =
627 sensorsAsyncResp->asyncResp->res
628 .jsonValue["Fans"];
629 for (const std::string& item : *collection)
630 {
631 sdbusplus::message::object_path itemPath(
632 item);
633 std::string itemName = itemPath.filename();
634 if (itemName.empty())
635 {
636 continue;
637 }
638 /*
639 todo(ed): merge patch that fixes the names
640 std::replace(itemName.begin(),
641 itemName.end(), '_', ' ');*/
642 auto schemaItem = std::ranges::find_if(
643 fanRedfish,
644 [itemName](const nlohmann::json& fan) {
645 return fan["Name"] == itemName;
646 });
647 if (schemaItem != fanRedfish.end())
648 {
649 nlohmann::json::object_t collectionId;
650 collectionId["@odata.id"] =
651 (*schemaItem)["@odata.id"];
652 redfishCollection.emplace_back(
653 std::move(collectionId));
654 }
655 else
656 {
657 BMCWEB_LOG_ERROR(
658 "failed to find fan in schema");
659 messages::internalError(
660 sensorsAsyncResp->asyncResp->res);
661 return;
662 }
663 }
664
665 size_t minNumNeeded =
666 collection->empty()
667 ? 0
668 : collection->size() - *allowedFailures;
669 nlohmann::json& jResp =
670 sensorsAsyncResp->asyncResp->res
671 .jsonValue["Redundancy"];
672
673 nlohmann::json::object_t redundancy;
674 boost::urls::url url = boost::urls::format(
675 "/redfish/v1/Chassis/{}/{}",
676 sensorsAsyncResp->chassisId,
677 sensorsAsyncResp->chassisSubNode);
678 url.set_fragment(
679 ("/Redundancy"_json_pointer / jResp.size())
680 .to_string());
681 redundancy["@odata.id"] = std::move(url);
682 redundancy["@odata.type"] =
683 "#Redundancy.v1_3_2.Redundancy";
684 redundancy["MinNumNeeded"] = minNumNeeded;
685 redundancy["Mode"] =
686 redundancy::RedundancyType::NPlusM;
687 redundancy["Name"] = name;
688 redundancy["RedundancySet"] = redfishCollection;
689 redundancy["Status"]["Health"] = health;
690 redundancy["Status"]["State"] =
691 resource::State::Enabled;
692
693 jResp.emplace_back(std::move(redundancy));
694 });
695 });
696 }
697 });
James Feist8bd25cc2019-03-15 15:14:00 -0700698}
699
Ed Tanousb5a76932020-09-29 16:16:58 -0700700inline void
Ed Tanous81ce6092020-12-17 16:54:55 +0000701 sortJSONResponse(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700702{
zhanghch058d1b46d2021-04-01 11:18:24 +0800703 nlohmann::json& response = sensorsAsyncResp->asyncResp->res.jsonValue;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700704 std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
Janet Adkins0c728b42024-08-29 11:09:10 -0500705 if (sensorsAsyncResp->chassisSubNode == sensors::powerNodeStr)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700706 {
707 sensorHeaders = {"Voltages", "PowerSupplies"};
708 }
709 for (const std::string& sensorGroup : sensorHeaders)
710 {
711 nlohmann::json::iterator entry = response.find(sensorGroup);
Ed Tanous4e196b92024-09-27 17:45:09 -0700712 if (entry == response.end())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700713 {
Ed Tanous4e196b92024-09-27 17:45:09 -0700714 continue;
715 }
716 nlohmann::json::array_t* arr =
717 entry->get_ptr<nlohmann::json::array_t*>();
718 if (arr == nullptr)
719 {
720 continue;
721 }
722 json_util::sortJsonArrayByKey(*arr, "Name");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700723
Ed Tanous4e196b92024-09-27 17:45:09 -0700724 // add the index counts to the end of each entry
725 size_t count = 0;
726 for (nlohmann::json& sensorJson : *entry)
727 {
728 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
729 if (odata == sensorJson.end())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700730 {
Ed Tanous4e196b92024-09-27 17:45:09 -0700731 continue;
732 }
733 std::string* value = odata->get_ptr<std::string*>();
734 if (value != nullptr)
735 {
736 *value += "/" + std::to_string(count);
737 sensorJson["MemberId"] = std::to_string(count);
738 count++;
739 sensorsAsyncResp->updateUri(sensorJson["Name"], *value);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700740 }
741 }
742 }
743}
744
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100745/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500746 * @brief Finds the inventory item with the specified object path.
747 * @param inventoryItems D-Bus inventory items associated with sensors.
748 * @param invItemObjPath D-Bus object path of inventory item.
749 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500750 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000751inline InventoryItem* findInventoryItem(
Ed Tanousb5a76932020-09-29 16:16:58 -0700752 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500753 const std::string& invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500754{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500755 for (InventoryItem& inventoryItem : *inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500756 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500757 if (inventoryItem.objectPath == invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500758 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500759 return &inventoryItem;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500760 }
761 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500762 return nullptr;
763}
764
765/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500766 * @brief Finds the inventory item associated with the specified sensor.
767 * @param inventoryItems D-Bus inventory items associated with sensors.
768 * @param sensorObjPath D-Bus object path of sensor.
769 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500770 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000771inline InventoryItem* findInventoryItemForSensor(
Ed Tanousb5a76932020-09-29 16:16:58 -0700772 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500773 const std::string& sensorObjPath)
774{
775 for (InventoryItem& inventoryItem : *inventoryItems)
776 {
Ed Tanousdb0d36e2023-06-30 10:37:05 -0700777 if (inventoryItem.sensors.contains(sensorObjPath))
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500778 {
779 return &inventoryItem;
780 }
781 }
782 return nullptr;
783}
784
785/**
Anthony Wilsond5005492019-07-31 16:34:17 -0500786 * @brief Finds the inventory item associated with the specified led path.
787 * @param inventoryItems D-Bus inventory items associated with sensors.
788 * @param ledObjPath D-Bus object path of led.
789 * @return Inventory item within vector, or nullptr if no match found.
790 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400791inline InventoryItem* findInventoryItemForLed(
792 std::vector<InventoryItem>& inventoryItems, const std::string& ledObjPath)
Anthony Wilsond5005492019-07-31 16:34:17 -0500793{
794 for (InventoryItem& inventoryItem : inventoryItems)
795 {
796 if (inventoryItem.ledObjectPath == ledObjPath)
797 {
798 return &inventoryItem;
799 }
800 }
801 return nullptr;
802}
803
804/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500805 * @brief Adds inventory item and associated sensor to specified vector.
806 *
807 * Adds a new InventoryItem to the vector if necessary. Searches for an
808 * existing InventoryItem with the specified object path. If not found, one is
809 * added to the vector.
810 *
811 * Next, the specified sensor is added to the set of sensors associated with the
812 * InventoryItem.
813 *
814 * @param inventoryItems D-Bus inventory items associated with sensors.
815 * @param invItemObjPath D-Bus object path of inventory item.
816 * @param sensorObjPath D-Bus object path of sensor
817 */
Ed Tanousb5a76932020-09-29 16:16:58 -0700818inline void addInventoryItem(
819 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
820 const std::string& invItemObjPath, const std::string& sensorObjPath)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500821{
822 // Look for inventory item in vector
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400823 InventoryItem* inventoryItem =
824 findInventoryItem(inventoryItems, invItemObjPath);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500825
826 // If inventory item doesn't exist in vector, add it
827 if (inventoryItem == nullptr)
828 {
829 inventoryItems->emplace_back(invItemObjPath);
830 inventoryItem = &(inventoryItems->back());
831 }
832
833 // Add sensor to set of sensors associated with inventory item
834 inventoryItem->sensors.emplace(sensorObjPath);
835}
836
837/**
838 * @brief Stores D-Bus data in the specified inventory item.
839 *
840 * Finds D-Bus data in the specified map of interfaces. Stores the data in the
841 * specified InventoryItem.
842 *
843 * This data is later used to provide sensor property values in the JSON
844 * response.
845 *
846 * @param inventoryItem Inventory item where data will be stored.
847 * @param interfacesDict Map containing D-Bus interfaces and their properties
848 * for the specified inventory item.
849 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000850inline void storeInventoryItemData(
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500851 InventoryItem& inventoryItem,
Michael Shen80f79a42023-08-24 13:41:53 +0000852 const dbus::utility::DBusInterfacesMap& interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500853{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500854 // Get properties from Inventory.Item interface
Ed Tanous711ac7a2021-12-20 09:34:41 -0800855
Ed Tanous9eb808c2022-01-25 10:19:23 -0800856 for (const auto& [interface, values] : interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500857 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800858 if (interface == "xyz.openbmc_project.Inventory.Item")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500859 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800860 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500861 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800862 if (name == "Present")
863 {
864 const bool* value = std::get_if<bool>(&dbusValue);
865 if (value != nullptr)
866 {
867 inventoryItem.isPresent = *value;
868 }
869 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500870 }
871 }
Ed Tanous711ac7a2021-12-20 09:34:41 -0800872 // Check if Inventory.Item.PowerSupply interface is present
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500873
Ed Tanous711ac7a2021-12-20 09:34:41 -0800874 if (interface == "xyz.openbmc_project.Inventory.Item.PowerSupply")
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500875 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800876 inventoryItem.isPowerSupply = true;
877 }
878
879 // Get properties from Inventory.Decorator.Asset interface
880 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
881 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800882 for (const auto& [name, dbusValue] : values)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500883 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800884 if (name == "Manufacturer")
885 {
886 const std::string* value =
887 std::get_if<std::string>(&dbusValue);
888 if (value != nullptr)
889 {
890 inventoryItem.manufacturer = *value;
891 }
892 }
893 if (name == "Model")
894 {
895 const std::string* value =
896 std::get_if<std::string>(&dbusValue);
897 if (value != nullptr)
898 {
899 inventoryItem.model = *value;
900 }
901 }
902 if (name == "SerialNumber")
903 {
904 const std::string* value =
905 std::get_if<std::string>(&dbusValue);
906 if (value != nullptr)
907 {
908 inventoryItem.serialNumber = *value;
909 }
910 }
911 if (name == "PartNumber")
912 {
913 const std::string* value =
914 std::get_if<std::string>(&dbusValue);
915 if (value != nullptr)
916 {
917 inventoryItem.partNumber = *value;
918 }
919 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500920 }
921 }
922
Ed Tanous711ac7a2021-12-20 09:34:41 -0800923 if (interface ==
924 "xyz.openbmc_project.State.Decorator.OperationalStatus")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500925 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800926 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500927 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800928 if (name == "Functional")
929 {
930 const bool* value = std::get_if<bool>(&dbusValue);
931 if (value != nullptr)
932 {
933 inventoryItem.isFunctional = *value;
934 }
935 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500936 }
937 }
938 }
939}
940
941/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500942 * @brief Gets D-Bus data for inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500943 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500944 * Uses the specified connections (services) to obtain D-Bus data for inventory
945 * items associated with sensors. Stores the resulting data in the
946 * inventoryItems vector.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500947 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500948 * This data is later used to provide sensor property values in the JSON
949 * response.
950 *
951 * Finds the inventory item data asynchronously. Invokes callback when data has
952 * been obtained.
953 *
954 * The callback must have the following signature:
955 * @code
Anthony Wilsond5005492019-07-31 16:34:17 -0500956 * callback(void)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500957 * @endcode
958 *
959 * This function is called recursively, obtaining data asynchronously from one
960 * connection in each call. This ensures the callback is not invoked until the
961 * last asynchronous function has completed.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500962 *
963 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500964 * @param inventoryItems D-Bus inventory items associated with sensors.
965 * @param invConnections Connections that provide data for the inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500966 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500967 * @param callback Callback to invoke when inventory data has been obtained.
968 * @param invConnectionsIndex Current index in invConnections. Only specified
969 * in recursive calls to this function.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500970 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500971template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -0700972void getInventoryItemsData(
Ed Tanousdaadfb22024-12-20 09:25:54 -0800973 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
974 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
975 const std::shared_ptr<std::set<std::string>>& invConnections,
976 Callback&& callback, size_t invConnectionsIndex = 0)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500977{
Ed Tanous62598e32023-07-17 17:06:25 -0700978 BMCWEB_LOG_DEBUG("getInventoryItemsData enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500979
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500980 // If no more connections left, call callback
981 if (invConnectionsIndex >= invConnections->size())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500982 {
Anthony Wilsond5005492019-07-31 16:34:17 -0500983 callback();
Ed Tanous62598e32023-07-17 17:06:25 -0700984 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500985 return;
986 }
987
988 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +0000989 auto it = invConnections->begin();
990 std::advance(it, invConnectionsIndex);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500991 if (it != invConnections->end())
992 {
993 const std::string& invConnection = *it;
994
George Liu5eb468d2023-06-20 17:03:24 +0800995 // Get all object paths and their interfaces for current connection
996 sdbusplus::message::object_path path("/xyz/openbmc_project/inventory");
997 dbus::utility::getManagedObjects(
998 invConnection, path,
999 [sensorsAsyncResp, inventoryItems, invConnections,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001000 callback = std::forward<Callback>(callback), invConnectionsIndex](
George Liu5eb468d2023-06-20 17:03:24 +08001001 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001002 const dbus::utility::ManagedObjectType& resp) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001003 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler enter");
1004 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001005 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001006 BMCWEB_LOG_ERROR(
1007 "getInventoryItemsData respHandler DBus error {}", ec);
1008 messages::internalError(sensorsAsyncResp->asyncResp->res);
1009 return;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001010 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001011
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001012 // Loop through returned object paths
1013 for (const auto& objDictEntry : resp)
1014 {
1015 const std::string& objPath =
1016 static_cast<const std::string&>(objDictEntry.first);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001017
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001018 // If this object path is one of the specified inventory
1019 // items
1020 InventoryItem* inventoryItem =
1021 findInventoryItem(inventoryItems, objPath);
1022 if (inventoryItem != nullptr)
1023 {
1024 // Store inventory data in InventoryItem
1025 storeInventoryItemData(*inventoryItem,
1026 objDictEntry.second);
1027 }
1028 }
1029
1030 // Recurse to get inventory item data from next connection
1031 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1032 invConnections, std::move(callback),
1033 invConnectionsIndex + 1);
1034
1035 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler exit");
1036 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001037 }
1038
Ed Tanous62598e32023-07-17 17:06:25 -07001039 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001040}
1041
1042/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001043 * @brief Gets connections that provide D-Bus data for inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001044 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001045 * Gets the D-Bus connections (services) that provide data for the inventory
1046 * items that are associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001047 *
1048 * Finds the connections asynchronously. Invokes callback when information has
1049 * been obtained.
1050 *
1051 * The callback must have the following signature:
1052 * @code
Nan Zhoufe04d492022-06-22 17:10:41 +00001053 * callback(std::shared_ptr<std::set<std::string>> invConnections)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001054 * @endcode
1055 *
1056 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001057 * @param inventoryItems D-Bus inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001058 * @param callback Callback to invoke when connections have been obtained.
1059 */
1060template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001061void getInventoryItemsConnections(
Ed Tanousb5a76932020-09-29 16:16:58 -07001062 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1063 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001064 Callback&& callback)
1065{
Ed Tanous62598e32023-07-17 17:06:25 -07001066 BMCWEB_LOG_DEBUG("getInventoryItemsConnections enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001067
1068 const std::string path = "/xyz/openbmc_project/inventory";
George Liue99073f2022-12-09 11:06:16 +08001069 constexpr std::array<std::string_view, 4> interfaces = {
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001070 "xyz.openbmc_project.Inventory.Item",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001071 "xyz.openbmc_project.Inventory.Item.PowerSupply",
1072 "xyz.openbmc_project.Inventory.Decorator.Asset",
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001073 "xyz.openbmc_project.State.Decorator.OperationalStatus"};
1074
George Liue99073f2022-12-09 11:06:16 +08001075 // Make call to ObjectMapper to find all inventory items
1076 dbus::utility::getSubTree(
1077 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001078 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001079 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001080 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001081 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001082 // Response handler for parsing output from GetSubTree
1083 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler enter");
1084 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001085 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001086 messages::internalError(sensorsAsyncResp->asyncResp->res);
1087 BMCWEB_LOG_ERROR(
1088 "getInventoryItemsConnections respHandler DBus error {}",
1089 ec);
1090 return;
1091 }
1092
1093 // Make unique list of connections for desired inventory items
1094 std::shared_ptr<std::set<std::string>> invConnections =
1095 std::make_shared<std::set<std::string>>();
1096
1097 // Loop through objects from GetSubTree
1098 for (const std::pair<std::string,
1099 std::vector<std::pair<
1100 std::string, std::vector<std::string>>>>&
1101 object : subtree)
1102 {
1103 // Check if object path is one of the specified inventory items
1104 const std::string& objPath = object.first;
1105 if (findInventoryItem(inventoryItems, objPath) != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001106 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001107 // Store all connections to inventory item
1108 for (const std::pair<std::string, std::vector<std::string>>&
1109 objData : object.second)
1110 {
1111 const std::string& invConnection = objData.first;
1112 invConnections->insert(invConnection);
1113 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001114 }
1115 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001116
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001117 callback(invConnections);
1118 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler exit");
1119 });
Ed Tanous62598e32023-07-17 17:06:25 -07001120 BMCWEB_LOG_DEBUG("getInventoryItemsConnections exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001121}
1122
1123/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001124 * @brief Gets associations from sensors to inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001125 *
1126 * Looks for ObjectMapper associations from the specified sensors to related
Anthony Wilsond5005492019-07-31 16:34:17 -05001127 * inventory items. Then finds the associations from those inventory items to
1128 * their LEDs, if any.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001129 *
1130 * Finds the inventory items asynchronously. Invokes callback when information
1131 * has been obtained.
1132 *
1133 * The callback must have the following signature:
1134 * @code
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001135 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001136 * @endcode
1137 *
1138 * @param sensorsAsyncResp Pointer to object holding response data.
1139 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001140 * implements ObjectManager.
1141 * @param callback Callback to invoke when inventory items have been obtained.
1142 */
1143template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001144void getInventoryItemAssociations(
Ed Tanousb5a76932020-09-29 16:16:58 -07001145 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001146 const std::shared_ptr<std::set<std::string>>& sensorNames,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001147 Callback&& callback)
1148{
Ed Tanous62598e32023-07-17 17:06:25 -07001149 BMCWEB_LOG_DEBUG("getInventoryItemAssociations enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001150
George Liu5eb468d2023-06-20 17:03:24 +08001151 // Call GetManagedObjects on the ObjectMapper to get all associations
1152 sdbusplus::message::object_path path("/");
1153 dbus::utility::getManagedObjects(
1154 "xyz.openbmc_project.ObjectMapper", path,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001155 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001156 sensorNames](const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001157 const dbus::utility::ManagedObjectType& resp) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001158 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler enter");
1159 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001160 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001161 BMCWEB_LOG_ERROR(
1162 "getInventoryItemAssociations respHandler DBus error {}",
1163 ec);
1164 messages::internalError(sensorsAsyncResp->asyncResp->res);
1165 return;
1166 }
1167
1168 // Create vector to hold list of inventory items
1169 std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1170 std::make_shared<std::vector<InventoryItem>>();
1171
1172 // Loop through returned object paths
1173 std::string sensorAssocPath;
1174 sensorAssocPath.reserve(128); // avoid memory allocations
1175 for (const auto& objDictEntry : resp)
1176 {
1177 const std::string& objPath =
1178 static_cast<const std::string&>(objDictEntry.first);
1179
1180 // If path is inventory association for one of the specified
1181 // sensors
1182 for (const std::string& sensorName : *sensorNames)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001183 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001184 sensorAssocPath = sensorName;
1185 sensorAssocPath += "/inventory";
1186 if (objPath == sensorAssocPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001187 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001188 // Get Association interface for object path
1189 for (const auto& [interface, values] :
1190 objDictEntry.second)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001191 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001192 if (interface == "xyz.openbmc_project.Association")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001193 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001194 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001195 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001196 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001197 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001198 const std::vector<std::string>*
1199 endpoints = std::get_if<
1200 std::vector<std::string>>(
1201 &value);
1202 if ((endpoints != nullptr) &&
1203 !endpoints->empty())
1204 {
1205 // Add inventory item to vector
1206 const std::string& invItemPath =
1207 endpoints->front();
1208 addInventoryItem(inventoryItems,
1209 invItemPath,
1210 sensorName);
1211 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001212 }
1213 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001214 }
1215 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001216 break;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001217 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001218 }
1219 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001220
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001221 // Now loop through the returned object paths again, this time to
1222 // find the leds associated with the inventory items we just found
1223 std::string inventoryAssocPath;
1224 inventoryAssocPath.reserve(128); // avoid memory allocations
1225 for (const auto& objDictEntry : resp)
Anthony Wilsond5005492019-07-31 16:34:17 -05001226 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001227 const std::string& objPath =
1228 static_cast<const std::string&>(objDictEntry.first);
1229
1230 for (InventoryItem& inventoryItem : *inventoryItems)
Anthony Wilsond5005492019-07-31 16:34:17 -05001231 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001232 inventoryAssocPath = inventoryItem.objectPath;
1233 inventoryAssocPath += "/leds";
1234 if (objPath == inventoryAssocPath)
Anthony Wilsond5005492019-07-31 16:34:17 -05001235 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001236 for (const auto& [interface, values] :
1237 objDictEntry.second)
Anthony Wilsond5005492019-07-31 16:34:17 -05001238 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001239 if (interface == "xyz.openbmc_project.Association")
Anthony Wilsond5005492019-07-31 16:34:17 -05001240 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001241 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001242 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001243 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001244 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001245 const std::vector<std::string>*
1246 endpoints = std::get_if<
1247 std::vector<std::string>>(
1248 &value);
1249 if ((endpoints != nullptr) &&
1250 !endpoints->empty())
1251 {
1252 // Add inventory item to vector
1253 // Store LED path in inventory item
1254 const std::string& ledPath =
1255 endpoints->front();
1256 inventoryItem.ledObjectPath =
1257 ledPath;
1258 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001259 }
1260 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001261 }
1262 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001263
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001264 break;
1265 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001266 }
1267 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001268 callback(inventoryItems);
1269 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler exit");
1270 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001271
Ed Tanous62598e32023-07-17 17:06:25 -07001272 BMCWEB_LOG_DEBUG("getInventoryItemAssociations exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001273}
1274
1275/**
Anthony Wilsond5005492019-07-31 16:34:17 -05001276 * @brief Gets D-Bus data for inventory item leds associated with sensors.
1277 *
1278 * Uses the specified connections (services) to obtain D-Bus data for inventory
1279 * item leds associated with sensors. Stores the resulting data in the
1280 * inventoryItems vector.
1281 *
1282 * This data is later used to provide sensor property values in the JSON
1283 * response.
1284 *
1285 * Finds the inventory item led data asynchronously. Invokes callback when data
1286 * has been obtained.
1287 *
1288 * The callback must have the following signature:
1289 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001290 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001291 * @endcode
1292 *
1293 * This function is called recursively, obtaining data asynchronously from one
1294 * connection in each call. This ensures the callback is not invoked until the
1295 * last asynchronous function has completed.
1296 *
1297 * @param sensorsAsyncResp Pointer to object holding response data.
1298 * @param inventoryItems D-Bus inventory items associated with sensors.
1299 * @param ledConnections Connections that provide data for the inventory leds.
1300 * @param callback Callback to invoke when inventory data has been obtained.
1301 * @param ledConnectionsIndex Current index in ledConnections. Only specified
1302 * in recursive calls to this function.
1303 */
1304template <typename Callback>
1305void getInventoryLedData(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001306 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1307 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
1308 const std::shared_ptr<std::map<std::string, std::string>>& ledConnections,
Anthony Wilsond5005492019-07-31 16:34:17 -05001309 Callback&& callback, size_t ledConnectionsIndex = 0)
1310{
Ed Tanous62598e32023-07-17 17:06:25 -07001311 BMCWEB_LOG_DEBUG("getInventoryLedData enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001312
1313 // If no more connections left, call callback
1314 if (ledConnectionsIndex >= ledConnections->size())
1315 {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001316 callback();
Ed Tanous62598e32023-07-17 17:06:25 -07001317 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001318 return;
1319 }
1320
1321 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +00001322 auto it = ledConnections->begin();
1323 std::advance(it, ledConnectionsIndex);
Anthony Wilsond5005492019-07-31 16:34:17 -05001324 if (it != ledConnections->end())
1325 {
1326 const std::string& ledPath = (*it).first;
1327 const std::string& ledConnection = (*it).second;
1328 // Response handler for Get State property
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001329 auto respHandler =
1330 [sensorsAsyncResp, inventoryItems, ledConnections, ledPath,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001331 callback = std::forward<Callback>(callback),
1332 ledConnectionsIndex](const boost::system::error_code& ec,
1333 const std::string& state) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001334 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler enter");
1335 if (ec)
1336 {
1337 BMCWEB_LOG_ERROR(
1338 "getInventoryLedData respHandler DBus error {}", ec);
1339 messages::internalError(sensorsAsyncResp->asyncResp->res);
1340 return;
1341 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001342
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001343 BMCWEB_LOG_DEBUG("Led state: {}", state);
1344 // Find inventory item with this LED object path
1345 InventoryItem* inventoryItem =
1346 findInventoryItemForLed(*inventoryItems, ledPath);
1347 if (inventoryItem != nullptr)
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001348 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001349 // Store LED state in InventoryItem
1350 if (state.ends_with("On"))
1351 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001352 inventoryItem->ledState = sensor_utils::LedState::ON;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001353 }
1354 else if (state.ends_with("Blink"))
1355 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001356 inventoryItem->ledState = sensor_utils::LedState::BLINK;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001357 }
1358 else if (state.ends_with("Off"))
1359 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001360 inventoryItem->ledState = sensor_utils::LedState::OFF;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001361 }
1362 else
1363 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001364 inventoryItem->ledState =
1365 sensor_utils::LedState::UNKNOWN;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001366 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001367 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001368
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001369 // Recurse to get LED data from next connection
1370 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1371 ledConnections, std::move(callback),
1372 ledConnectionsIndex + 1);
Anthony Wilsond5005492019-07-31 16:34:17 -05001373
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001374 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler exit");
1375 };
Anthony Wilsond5005492019-07-31 16:34:17 -05001376
1377 // Get the State property for the current LED
Ed Tanousdeae6a72024-11-11 21:58:57 -08001378 dbus::utility::getProperty<std::string>(
1379 ledConnection, ledPath, "xyz.openbmc_project.Led.Physical", "State",
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001380 std::move(respHandler));
Anthony Wilsond5005492019-07-31 16:34:17 -05001381 }
1382
Ed Tanous62598e32023-07-17 17:06:25 -07001383 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001384}
1385
1386/**
1387 * @brief Gets LED data for LEDs associated with given inventory items.
1388 *
1389 * Gets the D-Bus connections (services) that provide LED data for the LEDs
1390 * associated with the specified inventory items. Then gets the LED data from
1391 * each connection and stores it in the inventory item.
1392 *
1393 * This data is later used to provide sensor property values in the JSON
1394 * response.
1395 *
1396 * Finds the LED data asynchronously. Invokes callback when information has
1397 * been obtained.
1398 *
1399 * The callback must have the following signature:
1400 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001401 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001402 * @endcode
1403 *
1404 * @param sensorsAsyncResp Pointer to object holding response data.
1405 * @param inventoryItems D-Bus inventory items associated with sensors.
1406 * @param callback Callback to invoke when inventory items have been obtained.
1407 */
1408template <typename Callback>
1409void getInventoryLeds(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001410 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1411 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Anthony Wilsond5005492019-07-31 16:34:17 -05001412 Callback&& callback)
1413{
Ed Tanous62598e32023-07-17 17:06:25 -07001414 BMCWEB_LOG_DEBUG("getInventoryLeds enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001415
1416 const std::string path = "/xyz/openbmc_project";
George Liue99073f2022-12-09 11:06:16 +08001417 constexpr std::array<std::string_view, 1> interfaces = {
Anthony Wilsond5005492019-07-31 16:34:17 -05001418 "xyz.openbmc_project.Led.Physical"};
1419
George Liue99073f2022-12-09 11:06:16 +08001420 // Make call to ObjectMapper to find all inventory items
1421 dbus::utility::getSubTree(
1422 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001423 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001424 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001425 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001426 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001427 // Response handler for parsing output from GetSubTree
1428 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler enter");
1429 if (ec)
Anthony Wilsond5005492019-07-31 16:34:17 -05001430 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001431 messages::internalError(sensorsAsyncResp->asyncResp->res);
1432 BMCWEB_LOG_ERROR("getInventoryLeds respHandler DBus error {}",
1433 ec);
1434 return;
Anthony Wilsond5005492019-07-31 16:34:17 -05001435 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001436
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001437 // Build map of LED object paths to connections
1438 std::shared_ptr<std::map<std::string, std::string>> ledConnections =
1439 std::make_shared<std::map<std::string, std::string>>();
1440
1441 // Loop through objects from GetSubTree
1442 for (const std::pair<std::string,
1443 std::vector<std::pair<
1444 std::string, std::vector<std::string>>>>&
1445 object : subtree)
1446 {
1447 // Check if object path is LED for one of the specified
1448 // inventory items
1449 const std::string& ledPath = object.first;
1450 if (findInventoryItemForLed(*inventoryItems, ledPath) !=
1451 nullptr)
1452 {
1453 // Add mapping from ledPath to connection
1454 const std::string& connection =
1455 object.second.begin()->first;
1456 (*ledConnections)[ledPath] = connection;
1457 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", ledPath,
1458 connection);
1459 }
1460 }
1461
1462 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1463 ledConnections, std::move(callback));
1464 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler exit");
1465 });
Ed Tanous62598e32023-07-17 17:06:25 -07001466 BMCWEB_LOG_DEBUG("getInventoryLeds exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001467}
1468
1469/**
Gunnar Mills42cbe532019-08-15 15:26:54 -05001470 * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent
1471 *
1472 * Uses the specified connections (services) (currently assumes just one) to
1473 * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in
1474 * the inventoryItems vector. Only stores data in Power Supply inventoryItems.
1475 *
1476 * This data is later used to provide sensor property values in the JSON
1477 * response.
1478 *
1479 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1480 * when data has been obtained.
1481 *
1482 * The callback must have the following signature:
1483 * @code
1484 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1485 * @endcode
1486 *
1487 * @param sensorsAsyncResp Pointer to object holding response data.
1488 * @param inventoryItems D-Bus inventory items associated with sensors.
1489 * @param psAttributesConnections Connections that provide data for the Power
1490 * Supply Attributes
1491 * @param callback Callback to invoke when data has been obtained.
1492 */
1493template <typename Callback>
1494void getPowerSupplyAttributesData(
Ed Tanousb5a76932020-09-29 16:16:58 -07001495 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Ed Tanousdaadfb22024-12-20 09:25:54 -08001496 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001497 const std::map<std::string, std::string>& psAttributesConnections,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001498 Callback&& callback)
1499{
Ed Tanous62598e32023-07-17 17:06:25 -07001500 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001501
1502 if (psAttributesConnections.empty())
1503 {
Ed Tanous62598e32023-07-17 17:06:25 -07001504 BMCWEB_LOG_DEBUG("Can't find PowerSupplyAttributes, no connections!");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001505 callback(inventoryItems);
1506 return;
1507 }
1508
1509 // Assuming just one connection (service) for now
Nan Zhoufe04d492022-06-22 17:10:41 +00001510 auto it = psAttributesConnections.begin();
Gunnar Mills42cbe532019-08-15 15:26:54 -05001511
1512 const std::string& psAttributesPath = (*it).first;
1513 const std::string& psAttributesConnection = (*it).second;
1514
1515 // Response handler for Get DeratingFactor property
Patrick Williams5a39f772023-10-20 11:20:21 -05001516 auto respHandler = [sensorsAsyncResp, inventoryItems,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001517 callback = std::forward<Callback>(callback)](
Patrick Williams5a39f772023-10-20 11:20:21 -05001518 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001519 uint32_t value) mutable {
Ed Tanous62598e32023-07-17 17:06:25 -07001520 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001521 if (ec)
1522 {
Ed Tanous62598e32023-07-17 17:06:25 -07001523 BMCWEB_LOG_ERROR(
1524 "getPowerSupplyAttributesData respHandler DBus error {}", ec);
zhanghch058d1b46d2021-04-01 11:18:24 +08001525 messages::internalError(sensorsAsyncResp->asyncResp->res);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001526 return;
1527 }
1528
Ed Tanous62598e32023-07-17 17:06:25 -07001529 BMCWEB_LOG_DEBUG("PS EfficiencyPercent value: {}", value);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001530 // Store value in Power Supply Inventory Items
1531 for (InventoryItem& inventoryItem : *inventoryItems)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001532 {
Ed Tanous55f79e62022-01-25 11:26:16 -08001533 if (inventoryItem.isPowerSupply)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001534 {
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001535 inventoryItem.powerSupplyEfficiencyPercent =
1536 static_cast<int>(value);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001537 }
1538 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001539
Ed Tanous62598e32023-07-17 17:06:25 -07001540 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001541 callback(inventoryItems);
1542 };
1543
1544 // Get the DeratingFactor property for the PowerSupplyAttributes
1545 // Currently only property on the interface/only one we care about
Ed Tanousdeae6a72024-11-11 21:58:57 -08001546 dbus::utility::getProperty<uint32_t>(
1547 psAttributesConnection, psAttributesPath,
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001548 "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
1549 std::move(respHandler));
Gunnar Mills42cbe532019-08-15 15:26:54 -05001550
Ed Tanous62598e32023-07-17 17:06:25 -07001551 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001552}
1553
1554/**
1555 * @brief Gets the Power Supply Attributes such as EfficiencyPercent
1556 *
1557 * Gets the D-Bus connection (service) that provides Power Supply Attributes
1558 * data. Then gets the Power Supply Attributes data from the connection
1559 * (currently just assumes 1 connection) and stores the data in the inventory
1560 * item.
1561 *
1562 * This data is later used to provide sensor property values in the JSON
1563 * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish.
1564 *
1565 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1566 * when information has been obtained.
1567 *
1568 * The callback must have the following signature:
1569 * @code
1570 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1571 * @endcode
1572 *
1573 * @param sensorsAsyncResp Pointer to object holding response data.
1574 * @param inventoryItems D-Bus inventory items associated with sensors.
1575 * @param callback Callback to invoke when data has been obtained.
1576 */
1577template <typename Callback>
1578void getPowerSupplyAttributes(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001579 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1580 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001581 Callback&& callback)
1582{
Ed Tanous62598e32023-07-17 17:06:25 -07001583 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001584
1585 // Only need the power supply attributes when the Power Schema
Janet Adkins0c728b42024-08-29 11:09:10 -05001586 if (sensorsAsyncResp->chassisSubNode != sensors::powerNodeStr)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001587 {
Ed Tanous62598e32023-07-17 17:06:25 -07001588 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit since not Power");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001589 callback(inventoryItems);
1590 return;
1591 }
1592
George Liue99073f2022-12-09 11:06:16 +08001593 constexpr std::array<std::string_view, 1> interfaces = {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001594 "xyz.openbmc_project.Control.PowerSupplyAttributes"};
1595
George Liue99073f2022-12-09 11:06:16 +08001596 // Make call to ObjectMapper to find the PowerSupplyAttributes service
1597 dbus::utility::getSubTree(
1598 "/xyz/openbmc_project", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001599 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001600 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001601 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001602 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001603 // Response handler for parsing output from GetSubTree
1604 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler enter");
1605 if (ec)
1606 {
1607 messages::internalError(sensorsAsyncResp->asyncResp->res);
1608 BMCWEB_LOG_ERROR(
1609 "getPowerSupplyAttributes respHandler DBus error {}", ec);
1610 return;
1611 }
1612 if (subtree.empty())
1613 {
1614 BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
1615 callback(inventoryItems);
1616 return;
1617 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001618
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001619 // Currently we only support 1 power supply attribute, use this for
1620 // all the power supplies. Build map of object path to connection.
1621 // Assume just 1 connection and 1 path for now.
1622 std::map<std::string, std::string> psAttributesConnections;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001623
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001624 if (subtree[0].first.empty() || subtree[0].second.empty())
1625 {
1626 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1627 callback(inventoryItems);
1628 return;
1629 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001630
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001631 const std::string& psAttributesPath = subtree[0].first;
1632 const std::string& connection = subtree[0].second.begin()->first;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001633
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001634 if (connection.empty())
1635 {
1636 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1637 callback(inventoryItems);
1638 return;
1639 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001640
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001641 psAttributesConnections[psAttributesPath] = connection;
1642 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", psAttributesPath,
1643 connection);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001644
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001645 getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems,
1646 psAttributesConnections,
1647 std::move(callback));
1648 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler exit");
1649 });
Ed Tanous62598e32023-07-17 17:06:25 -07001650 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001651}
1652
1653/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001654 * @brief Gets inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001655 *
1656 * Finds the inventory items that are associated with the specified sensors.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001657 * Then gets D-Bus data for the inventory items, such as presence and VPD.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001658 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001659 * This data is later used to provide sensor property values in the JSON
1660 * response.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001661 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001662 * Finds the inventory items asynchronously. Invokes callback when the
1663 * inventory items have been obtained.
1664 *
1665 * The callback must have the following signature:
1666 * @code
1667 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1668 * @endcode
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001669 *
1670 * @param sensorsAsyncResp Pointer to object holding response data.
1671 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001672 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001673 * @param callback Callback to invoke when inventory items have been obtained.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001674 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001675template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001676inline void
Ed Tanousdaadfb22024-12-20 09:25:54 -08001677 getInventoryItems(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1678 const std::shared_ptr<std::set<std::string>>& sensorNames,
Ed Tanousd0090732022-10-04 17:22:56 -07001679 Callback&& callback)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001680{
Ed Tanous62598e32023-07-17 17:06:25 -07001681 BMCWEB_LOG_DEBUG("getInventoryItems enter");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001682 auto getInventoryItemAssociationsCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -07001683 [sensorsAsyncResp, callback = std::forward<Callback>(callback)](
Ed Tanousdaadfb22024-12-20 09:25:54 -08001684 const std::shared_ptr<std::vector<InventoryItem>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07001685 inventoryItems) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001686 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb enter");
1687 auto getInventoryItemsConnectionsCb =
1688 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001689 callback = std::forward<Callback>(callback)](
Ed Tanousdaadfb22024-12-20 09:25:54 -08001690 const std::shared_ptr<std::set<std::string>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07001691 invConnections) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001692 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb enter");
1693 auto getInventoryItemsDataCb =
1694 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001695 callback =
1696 std::forward<Callback>(callback)]() mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001697 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001698
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001699 auto getInventoryLedsCb =
1700 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001701 callback = std::forward<Callback>(
1702 callback)]() mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001703 BMCWEB_LOG_DEBUG(
1704 "getInventoryLedsCb enter");
1705 // Find Power Supply Attributes and get the
1706 // data
1707 getPowerSupplyAttributes(
1708 sensorsAsyncResp, inventoryItems,
1709 std::move(callback));
1710 BMCWEB_LOG_DEBUG("getInventoryLedsCb exit");
1711 };
1712
1713 // Find led connections and get the data
1714 getInventoryLeds(sensorsAsyncResp, inventoryItems,
1715 std::move(getInventoryLedsCb));
1716 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb exit");
1717 };
1718
1719 // Get inventory item data from connections
1720 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1721 invConnections,
1722 std::move(getInventoryItemsDataCb));
1723 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001724 };
1725
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001726 // Get connections that provide inventory item data
1727 getInventoryItemsConnections(
1728 sensorsAsyncResp, inventoryItems,
1729 std::move(getInventoryItemsConnectionsCb));
1730 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001731 };
1732
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001733 // Get associations from sensors to inventory items
Ed Tanousd0090732022-10-04 17:22:56 -07001734 getInventoryItemAssociations(sensorsAsyncResp, sensorNames,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001735 std::move(getInventoryItemAssociationsCb));
Ed Tanous62598e32023-07-17 17:06:25 -07001736 BMCWEB_LOG_DEBUG("getInventoryItems exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001737}
1738
1739/**
1740 * @brief Returns JSON PowerSupply object for the specified inventory item.
1741 *
1742 * Searches for a JSON PowerSupply object that matches the specified inventory
1743 * item. If one is not found, a new PowerSupply object is added to the JSON
1744 * array.
1745 *
1746 * Multiple sensors are often associated with one power supply inventory item.
1747 * As a result, multiple sensor values are stored in one JSON PowerSupply
1748 * object.
1749 *
1750 * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1751 * @param inventoryItem Inventory item for the power supply.
1752 * @param chassisId Chassis that contains the power supply.
1753 * @return JSON PowerSupply object for the specified inventory item.
1754 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001755inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001756 const InventoryItem& inventoryItem,
1757 const std::string& chassisId)
1758{
Ed Tanous18f8f602023-07-18 10:07:23 -07001759 std::string nameS;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001760 nameS.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001761 std::ranges::replace_copy(inventoryItem.name, nameS.begin(), '_', ' ');
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001762 // Check if matching PowerSupply object already exists in JSON array
1763 for (nlohmann::json& powerSupply : powerSupplyArray)
1764 {
Ed Tanous18f8f602023-07-18 10:07:23 -07001765 nlohmann::json::iterator nameIt = powerSupply.find("Name");
1766 if (nameIt == powerSupply.end())
1767 {
1768 continue;
1769 }
1770 const std::string* name = nameIt->get_ptr<std::string*>();
1771 if (name == nullptr)
1772 {
1773 continue;
1774 }
1775 if (nameS == *name)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001776 {
1777 return powerSupply;
1778 }
1779 }
1780
1781 // Add new PowerSupply object to JSON array
1782 powerSupplyArray.push_back({});
1783 nlohmann::json& powerSupply = powerSupplyArray.back();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001784 boost::urls::url url =
1785 boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
Willy Tueddfc432022-09-26 16:46:38 +00001786 url.set_fragment(("/PowerSupplies"_json_pointer).to_string());
1787 powerSupply["@odata.id"] = std::move(url);
Ed Tanous18f8f602023-07-18 10:07:23 -07001788 std::string escaped;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001789 escaped.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001790 std::ranges::replace_copy(inventoryItem.name, escaped.begin(), '_', ' ');
1791 powerSupply["Name"] = std::move(escaped);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001792 powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1793 powerSupply["Model"] = inventoryItem.model;
1794 powerSupply["PartNumber"] = inventoryItem.partNumber;
1795 powerSupply["SerialNumber"] = inventoryItem.serialNumber;
Janet Adkinsc9563602024-08-28 11:37:46 -05001796 sensor_utils::setLedState(powerSupply, &inventoryItem);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001797
Gunnar Mills42cbe532019-08-15 15:26:54 -05001798 if (inventoryItem.powerSupplyEfficiencyPercent >= 0)
1799 {
1800 powerSupply["EfficiencyPercent"] =
1801 inventoryItem.powerSupplyEfficiencyPercent;
1802 }
1803
Janet Adkinsc9563602024-08-28 11:37:46 -05001804 powerSupply["Status"]["State"] =
1805 sensor_utils::getState(&inventoryItem, true);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001806 const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1807 powerSupply["Status"]["Health"] = health;
1808
1809 return powerSupply;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001810}
1811
1812/**
Shawn McCarneyde629b62019-03-08 10:42:51 -06001813 * @brief Gets the values of the specified sensors.
1814 *
1815 * Stores the results as JSON in the SensorsAsyncResp.
1816 *
1817 * Gets the sensor values asynchronously. Stores the results later when the
1818 * information has been obtained.
1819 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001820 * The sensorNames set contains all requested sensors for the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001821 *
1822 * To minimize the number of DBus calls, the DBus method
1823 * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1824 * values of all sensors provided by a connection (service).
1825 *
1826 * The connections set contains all the connections that provide sensor values.
1827 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001828 * The InventoryItem vector contains D-Bus inventory items associated with the
1829 * sensors. Inventory item data is needed for some Redfish sensor properties.
1830 *
Shawn McCarneyde629b62019-03-08 10:42:51 -06001831 * @param SensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001832 * @param sensorNames All requested sensors within the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001833 * @param connections Connections that provide sensor values.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001834 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001835 * @param inventoryItems Inventory items associated with the sensors.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001836 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001837inline void getSensorData(
Ed Tanous81ce6092020-12-17 16:54:55 +00001838 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001839 const std::shared_ptr<std::set<std::string>>& sensorNames,
1840 const std::set<std::string>& connections,
Ed Tanousb5a76932020-09-29 16:16:58 -07001841 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001842{
Ed Tanous62598e32023-07-17 17:06:25 -07001843 BMCWEB_LOG_DEBUG("getSensorData enter");
Shawn McCarneyde629b62019-03-08 10:42:51 -06001844 // Get managed objects from all services exposing sensors
1845 for (const std::string& connection : connections)
1846 {
George Liu5eb468d2023-06-20 17:03:24 +08001847 sdbusplus::message::object_path sensorPath(
1848 "/xyz/openbmc_project/sensors");
1849 dbus::utility::getManagedObjects(
1850 connection, sensorPath,
Ed Tanous002d39b2022-05-31 08:59:27 -07001851 [sensorsAsyncResp, sensorNames,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001852 inventoryItems](const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -07001853 const dbus::utility::ManagedObjectType& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001854 BMCWEB_LOG_DEBUG("getManagedObjectsCb enter");
1855 if (ec)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001856 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001857 BMCWEB_LOG_ERROR("getManagedObjectsCb DBUS error: {}", ec);
1858 messages::internalError(sensorsAsyncResp->asyncResp->res);
1859 return;
1860 }
Janet Adkins0c728b42024-08-29 11:09:10 -05001861 auto chassisSubNode = sensor_utils::chassisSubNodeFromString(
1862 sensorsAsyncResp->chassisSubNode);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001863 // Go through all objects and update response with sensor data
1864 for (const auto& objDictEntry : resp)
1865 {
1866 const std::string& objPath =
1867 static_cast<const std::string&>(objDictEntry.first);
1868 BMCWEB_LOG_DEBUG("getManagedObjectsCb parsing object {}",
Ed Tanous62598e32023-07-17 17:06:25 -07001869 objPath);
Shawn McCarneyde629b62019-03-08 10:42:51 -06001870
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001871 std::vector<std::string> split;
1872 // Reserve space for
1873 // /xyz/openbmc_project/sensors/<name>/<subname>
1874 split.reserve(6);
1875 // NOLINTNEXTLINE
1876 bmcweb::split(split, objPath, '/');
1877 if (split.size() < 6)
Nan Zhou928fefb2022-03-28 08:45:00 -07001878 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001879 BMCWEB_LOG_ERROR("Got path that isn't long enough {}",
1880 objPath);
1881 continue;
Nan Zhou928fefb2022-03-28 08:45:00 -07001882 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001883 // These indexes aren't intuitive, as split puts an empty
1884 // string at the beginning
1885 const std::string& sensorType = split[4];
1886 const std::string& sensorName = split[5];
1887 BMCWEB_LOG_DEBUG("sensorName {} sensorType {}", sensorName,
1888 sensorType);
1889 if (sensorNames->find(objPath) == sensorNames->end())
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001890 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001891 BMCWEB_LOG_DEBUG("{} not in sensor list ", sensorName);
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001892 continue;
1893 }
1894
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001895 // Find inventory item (if any) associated with sensor
1896 InventoryItem* inventoryItem =
1897 findInventoryItemForSensor(inventoryItems, objPath);
1898
1899 const std::string& sensorSchema =
1900 sensorsAsyncResp->chassisSubNode;
1901
1902 nlohmann::json* sensorJson = nullptr;
1903
Janet Adkins0c728b42024-08-29 11:09:10 -05001904 if (sensorSchema == sensors::sensorsNodeStr &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001905 !sensorsAsyncResp->efficientExpand)
Nan Zhou928fefb2022-03-28 08:45:00 -07001906 {
Janet Adkins1516c212024-08-14 13:22:41 -05001907 std::string sensorId =
1908 redfish::sensor_utils::getSensorId(sensorName,
1909 sensorType);
Ed Tanous677bb752022-09-15 10:52:19 -07001910
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001911 sensorsAsyncResp->asyncResp->res
1912 .jsonValue["@odata.id"] = boost::urls::format(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001913 "/redfish/v1/Chassis/{}/{}/{}",
Ed Tanous677bb752022-09-15 10:52:19 -07001914 sensorsAsyncResp->chassisId,
1915 sensorsAsyncResp->chassisSubNode, sensorId);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001916 sensorJson =
1917 &(sensorsAsyncResp->asyncResp->res.jsonValue);
Nan Zhou928fefb2022-03-28 08:45:00 -07001918 }
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001919 else
1920 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001921 std::string fieldName;
1922 if (sensorsAsyncResp->efficientExpand)
1923 {
1924 fieldName = "Members";
1925 }
1926 else if (sensorType == "temperature")
1927 {
1928 fieldName = "Temperatures";
1929 }
1930 else if (sensorType == "fan" ||
1931 sensorType == "fan_tach" ||
1932 sensorType == "fan_pwm")
1933 {
1934 fieldName = "Fans";
1935 }
1936 else if (sensorType == "voltage")
1937 {
1938 fieldName = "Voltages";
1939 }
1940 else if (sensorType == "power")
1941 {
1942 if (sensorName == "total_power")
1943 {
1944 fieldName = "PowerControl";
1945 }
1946 else if ((inventoryItem != nullptr) &&
1947 (inventoryItem->isPowerSupply))
1948 {
1949 fieldName = "PowerSupplies";
1950 }
1951 else
1952 {
1953 // Other power sensors are in SensorCollection
1954 continue;
1955 }
1956 }
1957 else
1958 {
1959 BMCWEB_LOG_ERROR(
1960 "Unsure how to handle sensorType {}",
1961 sensorType);
1962 continue;
1963 }
1964
1965 nlohmann::json& tempArray =
1966 sensorsAsyncResp->asyncResp->res
1967 .jsonValue[fieldName];
1968 if (fieldName == "PowerControl")
1969 {
1970 if (tempArray.empty())
1971 {
1972 // Put multiple "sensors" into a single
1973 // PowerControl. Follows MemberId naming and
1974 // naming in power.hpp.
1975 nlohmann::json::object_t power;
1976 boost::urls::url url = boost::urls::format(
1977 "/redfish/v1/Chassis/{}/{}",
1978 sensorsAsyncResp->chassisId,
1979 sensorsAsyncResp->chassisSubNode);
1980 url.set_fragment(
1981 (""_json_pointer / fieldName / "0")
1982 .to_string());
1983 power["@odata.id"] = std::move(url);
1984 tempArray.emplace_back(std::move(power));
1985 }
1986 sensorJson = &(tempArray.back());
1987 }
1988 else if (fieldName == "PowerSupplies")
1989 {
1990 if (inventoryItem != nullptr)
1991 {
1992 sensorJson = &(getPowerSupply(
1993 tempArray, *inventoryItem,
1994 sensorsAsyncResp->chassisId));
1995 }
1996 }
1997 else if (fieldName == "Members")
1998 {
Janet Adkins1516c212024-08-14 13:22:41 -05001999 std::string sensorId =
2000 redfish::sensor_utils::getSensorId(sensorName,
2001 sensorType);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002002
2003 nlohmann::json::object_t member;
2004 member["@odata.id"] = boost::urls::format(
2005 "/redfish/v1/Chassis/{}/{}/{}",
2006 sensorsAsyncResp->chassisId,
2007 sensorsAsyncResp->chassisSubNode, sensorId);
2008 tempArray.emplace_back(std::move(member));
2009 sensorJson = &(tempArray.back());
2010 }
2011 else
2012 {
2013 nlohmann::json::object_t member;
2014 boost::urls::url url = boost::urls::format(
2015 "/redfish/v1/Chassis/{}/{}",
2016 sensorsAsyncResp->chassisId,
2017 sensorsAsyncResp->chassisSubNode);
2018 url.set_fragment(
2019 (""_json_pointer / fieldName).to_string());
2020 member["@odata.id"] = std::move(url);
2021 tempArray.emplace_back(std::move(member));
2022 sensorJson = &(tempArray.back());
2023 }
2024 }
2025
2026 if (sensorJson != nullptr)
2027 {
Janet Adkins0c728b42024-08-29 11:09:10 -05002028 objectInterfacesToJson(
2029 sensorName, sensorType, chassisSubNode,
2030 objDictEntry.second, *sensorJson, inventoryItem);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002031
2032 std::string path = "/xyz/openbmc_project/sensors/";
2033 path += sensorType;
2034 path += "/";
2035 path += sensorName;
2036 sensorsAsyncResp->addMetadata(*sensorJson, path);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002037 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002038 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002039 if (sensorsAsyncResp.use_count() == 1)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002040 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002041 sortJSONResponse(sensorsAsyncResp);
Janet Adkins0c728b42024-08-29 11:09:10 -05002042 if (chassisSubNode ==
2043 sensor_utils::ChassisSubNode::sensorsNode &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002044 sensorsAsyncResp->efficientExpand)
2045 {
2046 sensorsAsyncResp->asyncResp->res
2047 .jsonValue["Members@odata.count"] =
2048 sensorsAsyncResp->asyncResp->res
2049 .jsonValue["Members"]
2050 .size();
2051 }
Janet Adkins0c728b42024-08-29 11:09:10 -05002052 else if (chassisSubNode ==
2053 sensor_utils::ChassisSubNode::thermalNode)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002054 {
2055 populateFanRedundancy(sensorsAsyncResp);
2056 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002057 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002058 BMCWEB_LOG_DEBUG("getManagedObjectsCb exit");
2059 });
Ed Tanous23a21a12020-07-25 04:45:05 +00002060 }
Ed Tanous62598e32023-07-17 17:06:25 -07002061 BMCWEB_LOG_DEBUG("getSensorData exit");
Shawn McCarneyde629b62019-03-08 10:42:51 -06002062}
2063
Nan Zhoufe04d492022-06-22 17:10:41 +00002064inline void
2065 processSensorList(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
2066 const std::shared_ptr<std::set<std::string>>& sensorNames)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002067{
Nan Zhoufe04d492022-06-22 17:10:41 +00002068 auto getConnectionCb = [sensorsAsyncResp, sensorNames](
2069 const std::set<std::string>& connections) {
Ed Tanous62598e32023-07-17 17:06:25 -07002070 BMCWEB_LOG_DEBUG("getConnectionCb enter");
Ed Tanousd0090732022-10-04 17:22:56 -07002071 auto getInventoryItemsCb =
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002072 [sensorsAsyncResp, sensorNames, connections](
2073 const std::shared_ptr<std::vector<InventoryItem>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07002074 inventoryItems) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002075 BMCWEB_LOG_DEBUG("getInventoryItemsCb enter");
2076 // Get sensor data and store results in JSON
2077 getSensorData(sensorsAsyncResp, sensorNames, connections,
2078 inventoryItems);
2079 BMCWEB_LOG_DEBUG("getInventoryItemsCb exit");
2080 };
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002081
Ed Tanousd0090732022-10-04 17:22:56 -07002082 // Get inventory items associated with sensors
2083 getInventoryItems(sensorsAsyncResp, sensorNames,
2084 std::move(getInventoryItemsCb));
2085
Ed Tanous62598e32023-07-17 17:06:25 -07002086 BMCWEB_LOG_DEBUG("getConnectionCb exit");
Ed Tanous002d39b2022-05-31 08:59:27 -07002087 };
2088
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002089 // Get set of connections that provide sensor values
Ed Tanous81ce6092020-12-17 16:54:55 +00002090 getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002091}
2092
Shawn McCarneyde629b62019-03-08 10:42:51 -06002093/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002094 * @brief Entry point for retrieving sensors data related to requested
2095 * chassis.
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02002096 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002097 */
Ed Tanousb5a76932020-09-29 16:16:58 -07002098inline void
Ed Tanous81ce6092020-12-17 16:54:55 +00002099 getChassisData(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002100{
Ed Tanous62598e32023-07-17 17:06:25 -07002101 BMCWEB_LOG_DEBUG("getChassisData enter");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002102 auto getChassisCb =
Ed Tanous81ce6092020-12-17 16:54:55 +00002103 [sensorsAsyncResp](
Nan Zhoufe04d492022-06-22 17:10:41 +00002104 const std::shared_ptr<std::set<std::string>>& sensorNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002105 BMCWEB_LOG_DEBUG("getChassisCb enter");
2106 processSensorList(sensorsAsyncResp, sensorNames);
2107 BMCWEB_LOG_DEBUG("getChassisCb exit");
2108 };
Nan Zhou928fefb2022-03-28 08:45:00 -07002109 // SensorCollection doesn't contain the Redundancy property
Janet Adkins0c728b42024-08-29 11:09:10 -05002110 if (sensorsAsyncResp->chassisSubNode != sensors::sensorsNodeStr)
Nan Zhou928fefb2022-03-28 08:45:00 -07002111 {
2112 sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
2113 nlohmann::json::array();
2114 }
Shawn McCarney26f03892019-05-03 13:20:24 -05002115 // Get set of sensors in chassis
Ed Tanous7f1cc262022-08-09 13:33:57 -07002116 getChassis(sensorsAsyncResp->asyncResp, sensorsAsyncResp->chassisId,
2117 sensorsAsyncResp->chassisSubNode, sensorsAsyncResp->types,
2118 std::move(getChassisCb));
Ed Tanous62598e32023-07-17 17:06:25 -07002119 BMCWEB_LOG_DEBUG("getChassisData exit");
Ed Tanous271584a2019-07-09 16:24:22 -07002120}
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002121
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302122/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002123 * @brief Find the requested sensorName in the list of all sensors supplied by
2124 * the chassis node
2125 *
2126 * @param sensorName The sensor name supplied in the PATCH request
2127 * @param sensorsList The list of sensors managed by the chassis node
2128 * @param sensorsModified The list of sensors that were found as a result of
2129 * repeated calls to this function
2130 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002131inline bool findSensorNameUsingSensorPath(
2132 std::string_view sensorName, const std::set<std::string>& sensorsList,
2133 std::set<std::string>& sensorsModified)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002134{
Nan Zhoufe04d492022-06-22 17:10:41 +00002135 for (const auto& chassisSensor : sensorsList)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002136 {
George Liu28aa8de2021-02-01 15:13:30 +08002137 sdbusplus::message::object_path path(chassisSensor);
Ed Tanousb00dcc22021-02-23 12:52:50 -08002138 std::string thisSensorName = path.filename();
George Liu28aa8de2021-02-01 15:13:30 +08002139 if (thisSensorName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002140 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002141 continue;
2142 }
2143 if (thisSensorName == sensorName)
2144 {
2145 sensorsModified.emplace(chassisSensor);
2146 return true;
2147 }
2148 }
2149 return false;
2150}
2151
2152/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302153 * @brief Entry point for overriding sensor values of given sensor
2154 *
zhanghch058d1b46d2021-04-01 11:18:24 +08002155 * @param sensorAsyncResp response object
Carol Wang4bb3dc32019-10-17 18:15:02 +08002156 * @param allCollections Collections extract from sensors' request patch info
jayaprakash Mutyala91e130a2020-03-04 22:26:38 +00002157 * @param chassisSubNode Chassis Node for which the query has to happen
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302158 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002159inline void setSensorsOverride(
Ed Tanousb5a76932020-09-29 16:16:58 -07002160 const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
Ed Tanous08850572024-03-06 15:09:17 -08002161 std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>&
jayaprakash Mutyala397fd612020-02-06 23:33:34 +00002162 allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302163{
Ed Tanous62598e32023-07-17 17:06:25 -07002164 BMCWEB_LOG_INFO("setSensorsOverride for subNode{}",
2165 sensorAsyncResp->chassisSubNode);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302166
Ed Tanousd02aad32024-02-13 14:43:34 -08002167 std::string_view propertyValueName;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302168 std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302169 std::string memberId;
Ed Tanous543f4402022-01-06 13:12:53 -08002170 double value = 0.0;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302171 for (auto& collectionItems : allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302172 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302173 if (collectionItems.first == "Temperatures")
2174 {
2175 propertyValueName = "ReadingCelsius";
2176 }
2177 else if (collectionItems.first == "Fans")
2178 {
2179 propertyValueName = "Reading";
2180 }
2181 else
2182 {
2183 propertyValueName = "ReadingVolts";
2184 }
2185 for (auto& item : collectionItems.second)
2186 {
Myung Baeafc474a2024-10-09 00:53:29 -07002187 if (!json_util::readJsonObject( //
2188 item, sensorAsyncResp->asyncResp->res, //
2189 "MemberId", memberId, //
2190 propertyValueName, value //
2191 ))
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302192 {
2193 return;
2194 }
2195 overrideMap.emplace(memberId,
2196 std::make_pair(value, collectionItems.first));
2197 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302198 }
Carol Wang4bb3dc32019-10-17 18:15:02 +08002199
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002200 auto getChassisSensorListCb = [sensorAsyncResp, overrideMap,
2201 propertyValueNameStr =
2202 std::string(propertyValueName)](
2203 const std::shared_ptr<
2204 std::set<std::string>>& sensorsList) {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002205 // Match sensor names in the PATCH request to those managed by the
2206 // chassis node
Nan Zhoufe04d492022-06-22 17:10:41 +00002207 const std::shared_ptr<std::set<std::string>> sensorNames =
2208 std::make_shared<std::set<std::string>>();
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302209 for (const auto& item : overrideMap)
2210 {
2211 const auto& sensor = item.first;
Ed Tanousc71d6122022-11-29 14:10:32 -08002212 std::pair<std::string, std::string> sensorNameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002213 redfish::sensor_utils::splitSensorNameAndType(sensor);
Ed Tanousc71d6122022-11-29 14:10:32 -08002214 if (!findSensorNameUsingSensorPath(sensorNameType.second,
2215 *sensorsList, *sensorNames))
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302216 {
Ed Tanous62598e32023-07-17 17:06:25 -07002217 BMCWEB_LOG_INFO("Unable to find memberId {}", item.first);
zhanghch058d1b46d2021-04-01 11:18:24 +08002218 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302219 item.second.second, item.first);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302220 return;
2221 }
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302222 }
2223 // Get the connection to which the memberId belongs
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002224 auto getObjectsWithConnectionCb = [sensorAsyncResp, overrideMap,
2225 propertyValueNameStr](
2226 const std::set<
2227 std::string>& /*connections*/,
2228 const std::set<std::pair<
2229 std::string, std::string>>&
2230 objectsWithConnection) {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002231 if (objectsWithConnection.size() != overrideMap.size())
2232 {
Ed Tanous62598e32023-07-17 17:06:25 -07002233 BMCWEB_LOG_INFO(
2234 "Unable to find all objects with proper connection {} requested {}",
2235 objectsWithConnection.size(), overrideMap.size());
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002236 messages::resourceNotFound(
2237 sensorAsyncResp->asyncResp->res,
Janet Adkins0c728b42024-08-29 11:09:10 -05002238 sensorAsyncResp->chassisSubNode == sensors::thermalNodeStr
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002239 ? "Temperatures"
2240 : "Voltages",
2241 "Count");
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002242 return;
2243 }
2244 for (const auto& item : objectsWithConnection)
2245 {
2246 sdbusplus::message::object_path path(item.first);
2247 std::string sensorName = path.filename();
2248 if (sensorName.empty())
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302249 {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002250 messages::internalError(sensorAsyncResp->asyncResp->res);
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302251 return;
2252 }
Janet Adkins1516c212024-08-14 13:22:41 -05002253 std::string id = redfish::sensor_utils::getSensorId(
2254 sensorName, path.parent_path().filename());
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302255
Ban Feng3f5eb752023-06-29 09:19:20 +08002256 const auto& iterator = overrideMap.find(id);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002257 if (iterator == overrideMap.end())
2258 {
Ed Tanous62598e32023-07-17 17:06:25 -07002259 BMCWEB_LOG_INFO("Unable to find sensor object{}",
2260 item.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002261 messages::internalError(sensorAsyncResp->asyncResp->res);
2262 return;
2263 }
Ginu Georgee93abac2024-06-14 17:35:27 +05302264 setDbusProperty(sensorAsyncResp->asyncResp,
2265 propertyValueNameStr, item.second, item.first,
2266 "xyz.openbmc_project.Sensor.Value", "Value",
Ed Tanousd02aad32024-02-13 14:43:34 -08002267 iterator->second.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002268 }
2269 };
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302270 // Get object with connection for the given sensor name
2271 getObjectsWithConnection(sensorAsyncResp, sensorNames,
2272 std::move(getObjectsWithConnectionCb));
2273 };
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302274 // get full sensor list for the given chassisId and cross verify the sensor.
Ed Tanous7f1cc262022-08-09 13:33:57 -07002275 getChassis(sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId,
2276 sensorAsyncResp->chassisSubNode, sensorAsyncResp->types,
2277 std::move(getChassisSensorListCb));
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302278}
2279
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002280/**
2281 * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus
2282 * path of the sensor.
2283 *
2284 * Function builds valid Redfish response for sensor query of given chassis and
2285 * node. It then builds metadata about Redfish<->D-Bus correlations and provides
2286 * it to caller in a callback.
2287 *
2288 * @param chassis Chassis for which retrieval should be performed
Janet Adkinsc9563602024-08-28 11:37:46 -05002289 * @param node Node (group) of sensors. See sensor_utils::node for supported
2290 * values
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002291 * @param mapComplete Callback to be called with retrieval result
2292 */
Ed Tanous931edc72023-11-01 12:09:07 -07002293template <typename Callback>
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002294inline void retrieveUriToDbusMap(
2295 const std::string& chassis, const std::string& node, Callback&& mapComplete)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002296{
Ed Tanous02da7c52022-02-27 00:09:02 -08002297 decltype(sensors::paths)::const_iterator pathIt =
2298 std::find_if(sensors::paths.cbegin(), sensors::paths.cend(),
2299 [&node](auto&& val) { return val.first == node; });
2300 if (pathIt == sensors::paths.cend())
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002301 {
Ed Tanous62598e32023-07-17 17:06:25 -07002302 BMCWEB_LOG_ERROR("Wrong node provided : {}", node);
Ed Tanous6804b5c2023-10-31 14:50:03 -07002303 std::map<std::string, std::string> noop;
2304 mapComplete(boost::beast::http::status::bad_request, noop);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002305 return;
2306 }
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002307
Nan Zhou72374eb2022-01-27 17:06:51 -08002308 auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002309 auto callback =
2310 [asyncResp, mapCompleteCb = std::forward<Callback>(mapComplete)](
2311 const boost::beast::http::status status,
2312 const std::map<std::string, std::string>& uriToDbus) {
2313 mapCompleteCb(status, uriToDbus);
2314 };
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002315
2316 auto resp = std::make_shared<SensorsAsyncResp>(
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002317 asyncResp, chassis, pathIt->second, node, std::move(callback));
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002318 getChassisData(resp);
2319}
2320
Nan Zhoubacb2162022-04-06 11:28:32 -07002321namespace sensors
2322{
Nan Zhou928fefb2022-03-28 08:45:00 -07002323
Nan Zhoubacb2162022-04-06 11:28:32 -07002324inline void getChassisCallback(
Ed Tanousc1d019a2022-08-06 09:36:06 -07002325 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2326 std::string_view chassisId, std::string_view chassisSubNode,
Nan Zhoufe04d492022-06-22 17:10:41 +00002327 const std::shared_ptr<std::set<std::string>>& sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002328{
Ed Tanous62598e32023-07-17 17:06:25 -07002329 BMCWEB_LOG_DEBUG("getChassisCallback enter ");
Nan Zhoubacb2162022-04-06 11:28:32 -07002330
Ed Tanousc1d019a2022-08-06 09:36:06 -07002331 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
2332 for (const std::string& sensor : *sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002333 {
Ed Tanous62598e32023-07-17 17:06:25 -07002334 BMCWEB_LOG_DEBUG("Adding sensor: {}", sensor);
Nan Zhoubacb2162022-04-06 11:28:32 -07002335
2336 sdbusplus::message::object_path path(sensor);
2337 std::string sensorName = path.filename();
2338 if (sensorName.empty())
2339 {
Ed Tanous62598e32023-07-17 17:06:25 -07002340 BMCWEB_LOG_ERROR("Invalid sensor path: {}", sensor);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002341 messages::internalError(asyncResp->res);
Nan Zhoubacb2162022-04-06 11:28:32 -07002342 return;
2343 }
Ed Tanousc1d019a2022-08-06 09:36:06 -07002344 std::string type = path.parent_path().filename();
Janet Adkins1516c212024-08-14 13:22:41 -05002345 std::string id = redfish::sensor_utils::getSensorId(sensorName, type);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002346
Ed Tanous14766872022-03-15 10:44:42 -07002347 nlohmann::json::object_t member;
Ed Tanousef4c65b2023-04-24 15:28:50 -07002348 member["@odata.id"] = boost::urls::format(
2349 "/redfish/v1/Chassis/{}/{}/{}", chassisId, chassisSubNode, id);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002350
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002351 entriesArray.emplace_back(std::move(member));
Nan Zhoubacb2162022-04-06 11:28:32 -07002352 }
2353
Ed Tanousc1d019a2022-08-06 09:36:06 -07002354 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Ed Tanous62598e32023-07-17 17:06:25 -07002355 BMCWEB_LOG_DEBUG("getChassisCallback exit");
Nan Zhoubacb2162022-04-06 11:28:32 -07002356}
Nan Zhoue6bd8462022-06-01 04:35:35 +00002357
Ed Tanousac106bf2023-06-07 09:24:59 -07002358inline void handleSensorCollectionGet(
2359 App& app, const crow::Request& req,
2360 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2361 const std::string& chassisId)
Nan Zhoude167a62022-06-01 04:47:45 +00002362{
2363 query_param::QueryCapabilities capabilities = {
2364 .canDelegateExpandLevel = 1,
2365 };
2366 query_param::Query delegatedQuery;
Ed Tanousac106bf2023-06-07 09:24:59 -07002367 if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
Nan Zhoude167a62022-06-01 04:47:45 +00002368 delegatedQuery, capabilities))
2369 {
2370 return;
2371 }
2372
2373 if (delegatedQuery.expandType != query_param::ExpandType::None)
2374 {
2375 // we perform efficient expand.
Ed Tanousac106bf2023-06-07 09:24:59 -07002376 auto sensorsAsyncResp = std::make_shared<SensorsAsyncResp>(
2377 asyncResp, chassisId, sensors::dbus::sensorPaths,
Janet Adkins0c728b42024-08-29 11:09:10 -05002378 sensors::sensorsNodeStr,
Nan Zhoude167a62022-06-01 04:47:45 +00002379 /*efficientExpand=*/true);
Ed Tanousac106bf2023-06-07 09:24:59 -07002380 getChassisData(sensorsAsyncResp);
Nan Zhoude167a62022-06-01 04:47:45 +00002381
Ed Tanous62598e32023-07-17 17:06:25 -07002382 BMCWEB_LOG_DEBUG(
2383 "SensorCollection doGet exit via efficient expand handler");
Nan Zhoude167a62022-06-01 04:47:45 +00002384 return;
Ed Tanous0bad3202022-06-02 13:53:59 -07002385 }
Nan Zhoude167a62022-06-01 04:47:45 +00002386
Nan Zhoude167a62022-06-01 04:47:45 +00002387 // We get all sensors as hyperlinkes in the chassis (this
2388 // implies we reply on the default query parameters handler)
Janet Adkins0c728b42024-08-29 11:09:10 -05002389 getChassis(asyncResp, chassisId, sensors::sensorsNodeStr, dbus::sensorPaths,
Ed Tanousac106bf2023-06-07 09:24:59 -07002390 std::bind_front(sensors::getChassisCallback, asyncResp,
Janet Adkins0c728b42024-08-29 11:09:10 -05002391 chassisId, sensors::sensorsNodeStr));
Ed Tanousc1d019a2022-08-06 09:36:06 -07002392}
Ed Tanous7f1cc262022-08-09 13:33:57 -07002393
Ed Tanousc1d019a2022-08-06 09:36:06 -07002394inline void
2395 getSensorFromDbus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2396 const std::string& sensorPath,
2397 const ::dbus::utility::MapperGetObject& mapperResponse)
2398{
2399 if (mapperResponse.size() != 1)
2400 {
2401 messages::internalError(asyncResp->res);
2402 return;
2403 }
2404 const auto& valueIface = *mapperResponse.begin();
2405 const std::string& connectionName = valueIface.first;
Ed Tanous62598e32023-07-17 17:06:25 -07002406 BMCWEB_LOG_DEBUG("Looking up {}", connectionName);
2407 BMCWEB_LOG_DEBUG("Path {}", sensorPath);
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +02002408
Ed Tanousdeae6a72024-11-11 21:58:57 -08002409 ::dbus::utility::getAllProperties(
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +02002410 *crow::connections::systemBus, connectionName, sensorPath, "",
Ed Tanousc1d019a2022-08-06 09:36:06 -07002411 [asyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002412 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002413 const ::dbus::utility::DBusPropertiesMap& valuesDict) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002414 if (ec)
2415 {
2416 messages::internalError(asyncResp->res);
2417 return;
2418 }
2419 sdbusplus::message::object_path path(sensorPath);
2420 std::string name = path.filename();
2421 path = path.parent_path();
2422 std::string type = path.filename();
Janet Adkinsc9563602024-08-28 11:37:46 -05002423 sensor_utils::objectPropertiesToJson(
Janet Adkins0c728b42024-08-29 11:09:10 -05002424 name, type, sensor_utils::ChassisSubNode::sensorsNode,
2425 valuesDict, asyncResp->res.jsonValue, nullptr);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002426 });
Nan Zhoude167a62022-06-01 04:47:45 +00002427}
2428
Nan Zhoue6bd8462022-06-01 04:35:35 +00002429inline void handleSensorGet(App& app, const crow::Request& req,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002430 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous677bb752022-09-15 10:52:19 -07002431 const std::string& chassisId,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002432 const std::string& sensorId)
Nan Zhoue6bd8462022-06-01 04:35:35 +00002433{
Ed Tanousc1d019a2022-08-06 09:36:06 -07002434 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Nan Zhoue6bd8462022-06-01 04:35:35 +00002435 {
2436 return;
2437 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002438 std::pair<std::string, std::string> nameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002439 redfish::sensor_utils::splitSensorNameAndType(sensorId);
Ed Tanousc71d6122022-11-29 14:10:32 -08002440 if (nameType.first.empty() || nameType.second.empty())
Ed Tanousc1d019a2022-08-06 09:36:06 -07002441 {
2442 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2443 return;
2444 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002445
Ed Tanousef4c65b2023-04-24 15:28:50 -07002446 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2447 "/redfish/v1/Chassis/{}/Sensors/{}", chassisId, sensorId);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002448
Ed Tanous62598e32023-07-17 17:06:25 -07002449 BMCWEB_LOG_DEBUG("Sensor doGet enter");
Nan Zhoue6bd8462022-06-01 04:35:35 +00002450
George Liu2b731192023-01-11 16:27:13 +08002451 constexpr std::array<std::string_view, 1> interfaces = {
Nan Zhoue6bd8462022-06-01 04:35:35 +00002452 "xyz.openbmc_project.Sensor.Value"};
Ed Tanousc71d6122022-11-29 14:10:32 -08002453 std::string sensorPath = "/xyz/openbmc_project/sensors/" + nameType.first +
2454 '/' + nameType.second;
Nan Zhoue6bd8462022-06-01 04:35:35 +00002455 // Get a list of all of the sensors that implement Sensor.Value
2456 // and get the path and service name associated with the sensor
George Liu2b731192023-01-11 16:27:13 +08002457 ::dbus::utility::getDbusObject(
2458 sensorPath, interfaces,
Myung Baeaec0ec32023-05-31 15:10:01 -05002459 [asyncResp, sensorId,
George Liu2b731192023-01-11 16:27:13 +08002460 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002461 const ::dbus::utility::MapperGetObject& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002462 BMCWEB_LOG_DEBUG("respHandler1 enter");
2463 if (ec == boost::system::errc::io_error)
2464 {
2465 BMCWEB_LOG_WARNING("Sensor not found from getSensorPaths");
2466 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2467 return;
2468 }
2469 if (ec)
2470 {
2471 messages::internalError(asyncResp->res);
2472 BMCWEB_LOG_ERROR(
2473 "Sensor getSensorPaths resp_handler: Dbus error {}", ec);
2474 return;
2475 }
2476 getSensorFromDbus(asyncResp, sensorPath, subtree);
2477 BMCWEB_LOG_DEBUG("respHandler1 exit");
2478 });
Nan Zhoue6bd8462022-06-01 04:35:35 +00002479}
2480
Nan Zhoubacb2162022-04-06 11:28:32 -07002481} // namespace sensors
2482
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002483inline void requestRoutesSensorCollection(App& app)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002484{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002485 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
Ed Tanoused398212021-06-09 17:05:54 -07002486 .privileges(redfish::privileges::getSensorCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002487 .methods(boost::beast::http::verb::get)(
Nan Zhoude167a62022-06-01 04:47:45 +00002488 std::bind_front(sensors::handleSensorCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002489}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002490
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002491inline void requestRoutesSensor(App& app)
2492{
2493 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002494 .privileges(redfish::privileges::getSensor)
Ed Tanous002d39b2022-05-31 08:59:27 -07002495 .methods(boost::beast::http::verb::get)(
Nan Zhoue6bd8462022-06-01 04:35:35 +00002496 std::bind_front(sensors::handleSensorGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002497}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002498
Ed Tanous1abe55e2018-09-05 08:30:59 -07002499} // namespace redfish