blob: f344220b0158e071a5c1e72757ef68f8e35ffc81 [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>
Nan Zhoufe04d492022-06-22 17:10:41 +0000306void getConnections(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
307 const std::shared_ptr<std::set<std::string>> sensorNames,
308 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 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400558 sdbusplus::asio::getAllProperties(
559 *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(
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500973 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500974 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Ed Tanousd0090732022-10-04 17:22:56 -0700975 std::shared_ptr<std::set<std::string>> invConnections, Callback&& callback,
976 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(
1306 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1307 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001308 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
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001378 sdbusplus::asio::getProperty<std::string>(
1379 *crow::connections::systemBus, ledConnection, ledPath,
1380 "xyz.openbmc_project.Led.Physical", "State",
1381 std::move(respHandler));
Anthony Wilsond5005492019-07-31 16:34:17 -05001382 }
1383
Ed Tanous62598e32023-07-17 17:06:25 -07001384 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001385}
1386
1387/**
1388 * @brief Gets LED data for LEDs associated with given inventory items.
1389 *
1390 * Gets the D-Bus connections (services) that provide LED data for the LEDs
1391 * associated with the specified inventory items. Then gets the LED data from
1392 * each connection and stores it in the inventory item.
1393 *
1394 * This data is later used to provide sensor property values in the JSON
1395 * response.
1396 *
1397 * Finds the LED data asynchronously. Invokes callback when information has
1398 * been obtained.
1399 *
1400 * The callback must have the following signature:
1401 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001402 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001403 * @endcode
1404 *
1405 * @param sensorsAsyncResp Pointer to object holding response data.
1406 * @param inventoryItems D-Bus inventory items associated with sensors.
1407 * @param callback Callback to invoke when inventory items have been obtained.
1408 */
1409template <typename Callback>
1410void getInventoryLeds(
1411 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1412 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1413 Callback&& callback)
1414{
Ed Tanous62598e32023-07-17 17:06:25 -07001415 BMCWEB_LOG_DEBUG("getInventoryLeds enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001416
1417 const std::string path = "/xyz/openbmc_project";
George Liue99073f2022-12-09 11:06:16 +08001418 constexpr std::array<std::string_view, 1> interfaces = {
Anthony Wilsond5005492019-07-31 16:34:17 -05001419 "xyz.openbmc_project.Led.Physical"};
1420
George Liue99073f2022-12-09 11:06:16 +08001421 // Make call to ObjectMapper to find all inventory items
1422 dbus::utility::getSubTree(
1423 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001424 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001425 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001426 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001427 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001428 // Response handler for parsing output from GetSubTree
1429 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler enter");
1430 if (ec)
Anthony Wilsond5005492019-07-31 16:34:17 -05001431 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001432 messages::internalError(sensorsAsyncResp->asyncResp->res);
1433 BMCWEB_LOG_ERROR("getInventoryLeds respHandler DBus error {}",
1434 ec);
1435 return;
Anthony Wilsond5005492019-07-31 16:34:17 -05001436 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001437
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001438 // Build map of LED object paths to connections
1439 std::shared_ptr<std::map<std::string, std::string>> ledConnections =
1440 std::make_shared<std::map<std::string, std::string>>();
1441
1442 // Loop through objects from GetSubTree
1443 for (const std::pair<std::string,
1444 std::vector<std::pair<
1445 std::string, std::vector<std::string>>>>&
1446 object : subtree)
1447 {
1448 // Check if object path is LED for one of the specified
1449 // inventory items
1450 const std::string& ledPath = object.first;
1451 if (findInventoryItemForLed(*inventoryItems, ledPath) !=
1452 nullptr)
1453 {
1454 // Add mapping from ledPath to connection
1455 const std::string& connection =
1456 object.second.begin()->first;
1457 (*ledConnections)[ledPath] = connection;
1458 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", ledPath,
1459 connection);
1460 }
1461 }
1462
1463 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1464 ledConnections, std::move(callback));
1465 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler exit");
1466 });
Ed Tanous62598e32023-07-17 17:06:25 -07001467 BMCWEB_LOG_DEBUG("getInventoryLeds exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001468}
1469
1470/**
Gunnar Mills42cbe532019-08-15 15:26:54 -05001471 * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent
1472 *
1473 * Uses the specified connections (services) (currently assumes just one) to
1474 * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in
1475 * the inventoryItems vector. Only stores data in Power Supply inventoryItems.
1476 *
1477 * This data is later used to provide sensor property values in the JSON
1478 * response.
1479 *
1480 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1481 * when data has been obtained.
1482 *
1483 * The callback must have the following signature:
1484 * @code
1485 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1486 * @endcode
1487 *
1488 * @param sensorsAsyncResp Pointer to object holding response data.
1489 * @param inventoryItems D-Bus inventory items associated with sensors.
1490 * @param psAttributesConnections Connections that provide data for the Power
1491 * Supply Attributes
1492 * @param callback Callback to invoke when data has been obtained.
1493 */
1494template <typename Callback>
1495void getPowerSupplyAttributesData(
Ed Tanousb5a76932020-09-29 16:16:58 -07001496 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001497 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001498 const std::map<std::string, std::string>& psAttributesConnections,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001499 Callback&& callback)
1500{
Ed Tanous62598e32023-07-17 17:06:25 -07001501 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001502
1503 if (psAttributesConnections.empty())
1504 {
Ed Tanous62598e32023-07-17 17:06:25 -07001505 BMCWEB_LOG_DEBUG("Can't find PowerSupplyAttributes, no connections!");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001506 callback(inventoryItems);
1507 return;
1508 }
1509
1510 // Assuming just one connection (service) for now
Nan Zhoufe04d492022-06-22 17:10:41 +00001511 auto it = psAttributesConnections.begin();
Gunnar Mills42cbe532019-08-15 15:26:54 -05001512
1513 const std::string& psAttributesPath = (*it).first;
1514 const std::string& psAttributesConnection = (*it).second;
1515
1516 // Response handler for Get DeratingFactor property
Patrick Williams5a39f772023-10-20 11:20:21 -05001517 auto respHandler = [sensorsAsyncResp, inventoryItems,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001518 callback = std::forward<Callback>(callback)](
Patrick Williams5a39f772023-10-20 11:20:21 -05001519 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001520 uint32_t value) mutable {
Ed Tanous62598e32023-07-17 17:06:25 -07001521 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001522 if (ec)
1523 {
Ed Tanous62598e32023-07-17 17:06:25 -07001524 BMCWEB_LOG_ERROR(
1525 "getPowerSupplyAttributesData respHandler DBus error {}", ec);
zhanghch058d1b46d2021-04-01 11:18:24 +08001526 messages::internalError(sensorsAsyncResp->asyncResp->res);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001527 return;
1528 }
1529
Ed Tanous62598e32023-07-17 17:06:25 -07001530 BMCWEB_LOG_DEBUG("PS EfficiencyPercent value: {}", value);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001531 // Store value in Power Supply Inventory Items
1532 for (InventoryItem& inventoryItem : *inventoryItems)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001533 {
Ed Tanous55f79e62022-01-25 11:26:16 -08001534 if (inventoryItem.isPowerSupply)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001535 {
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001536 inventoryItem.powerSupplyEfficiencyPercent =
1537 static_cast<int>(value);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001538 }
1539 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001540
Ed Tanous62598e32023-07-17 17:06:25 -07001541 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001542 callback(inventoryItems);
1543 };
1544
1545 // Get the DeratingFactor property for the PowerSupplyAttributes
1546 // Currently only property on the interface/only one we care about
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001547 sdbusplus::asio::getProperty<uint32_t>(
1548 *crow::connections::systemBus, psAttributesConnection, psAttributesPath,
1549 "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
1550 std::move(respHandler));
Gunnar Mills42cbe532019-08-15 15:26:54 -05001551
Ed Tanous62598e32023-07-17 17:06:25 -07001552 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001553}
1554
1555/**
1556 * @brief Gets the Power Supply Attributes such as EfficiencyPercent
1557 *
1558 * Gets the D-Bus connection (service) that provides Power Supply Attributes
1559 * data. Then gets the Power Supply Attributes data from the connection
1560 * (currently just assumes 1 connection) and stores the data in the inventory
1561 * item.
1562 *
1563 * This data is later used to provide sensor property values in the JSON
1564 * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish.
1565 *
1566 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1567 * when information has been obtained.
1568 *
1569 * The callback must have the following signature:
1570 * @code
1571 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1572 * @endcode
1573 *
1574 * @param sensorsAsyncResp Pointer to object holding response data.
1575 * @param inventoryItems D-Bus inventory items associated with sensors.
1576 * @param callback Callback to invoke when data has been obtained.
1577 */
1578template <typename Callback>
1579void getPowerSupplyAttributes(
1580 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1581 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1582 Callback&& callback)
1583{
Ed Tanous62598e32023-07-17 17:06:25 -07001584 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001585
1586 // Only need the power supply attributes when the Power Schema
Janet Adkins0c728b42024-08-29 11:09:10 -05001587 if (sensorsAsyncResp->chassisSubNode != sensors::powerNodeStr)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001588 {
Ed Tanous62598e32023-07-17 17:06:25 -07001589 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit since not Power");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001590 callback(inventoryItems);
1591 return;
1592 }
1593
George Liue99073f2022-12-09 11:06:16 +08001594 constexpr std::array<std::string_view, 1> interfaces = {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001595 "xyz.openbmc_project.Control.PowerSupplyAttributes"};
1596
George Liue99073f2022-12-09 11:06:16 +08001597 // Make call to ObjectMapper to find the PowerSupplyAttributes service
1598 dbus::utility::getSubTree(
1599 "/xyz/openbmc_project", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001600 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001601 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001602 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001603 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001604 // Response handler for parsing output from GetSubTree
1605 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler enter");
1606 if (ec)
1607 {
1608 messages::internalError(sensorsAsyncResp->asyncResp->res);
1609 BMCWEB_LOG_ERROR(
1610 "getPowerSupplyAttributes respHandler DBus error {}", ec);
1611 return;
1612 }
1613 if (subtree.empty())
1614 {
1615 BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
1616 callback(inventoryItems);
1617 return;
1618 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001619
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001620 // Currently we only support 1 power supply attribute, use this for
1621 // all the power supplies. Build map of object path to connection.
1622 // Assume just 1 connection and 1 path for now.
1623 std::map<std::string, std::string> psAttributesConnections;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001624
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001625 if (subtree[0].first.empty() || subtree[0].second.empty())
1626 {
1627 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1628 callback(inventoryItems);
1629 return;
1630 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001631
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001632 const std::string& psAttributesPath = subtree[0].first;
1633 const std::string& connection = subtree[0].second.begin()->first;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001634
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001635 if (connection.empty())
1636 {
1637 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1638 callback(inventoryItems);
1639 return;
1640 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001641
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001642 psAttributesConnections[psAttributesPath] = connection;
1643 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", psAttributesPath,
1644 connection);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001645
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001646 getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems,
1647 psAttributesConnections,
1648 std::move(callback));
1649 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler exit");
1650 });
Ed Tanous62598e32023-07-17 17:06:25 -07001651 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001652}
1653
1654/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001655 * @brief Gets inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001656 *
1657 * Finds the inventory items that are associated with the specified sensors.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001658 * Then gets D-Bus data for the inventory items, such as presence and VPD.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001659 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001660 * This data is later used to provide sensor property values in the JSON
1661 * response.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001662 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001663 * Finds the inventory items asynchronously. Invokes callback when the
1664 * inventory items have been obtained.
1665 *
1666 * The callback must have the following signature:
1667 * @code
1668 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1669 * @endcode
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001670 *
1671 * @param sensorsAsyncResp Pointer to object holding response data.
1672 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001673 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001674 * @param callback Callback to invoke when inventory items have been obtained.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001675 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001676template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001677inline void
Ed Tanousd0090732022-10-04 17:22:56 -07001678 getInventoryItems(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1679 const std::shared_ptr<std::set<std::string>> sensorNames,
1680 Callback&& callback)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001681{
Ed Tanous62598e32023-07-17 17:06:25 -07001682 BMCWEB_LOG_DEBUG("getInventoryItems enter");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001683 auto getInventoryItemAssociationsCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -07001684 [sensorsAsyncResp, callback = std::forward<Callback>(callback)](
Ed Tanous4e0d8782024-09-06 15:16:41 -07001685 std::shared_ptr<std::vector<InventoryItem>>
1686 inventoryItems) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001687 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb enter");
1688 auto getInventoryItemsConnectionsCb =
1689 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001690 callback = std::forward<Callback>(callback)](
1691 std::shared_ptr<std::set<std::string>>
1692 invConnections) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001693 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb enter");
1694 auto getInventoryItemsDataCb =
1695 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001696 callback =
1697 std::forward<Callback>(callback)]() mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001698 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001699
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001700 auto getInventoryLedsCb =
1701 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001702 callback = std::forward<Callback>(
1703 callback)]() mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001704 BMCWEB_LOG_DEBUG(
1705 "getInventoryLedsCb enter");
1706 // Find Power Supply Attributes and get the
1707 // data
1708 getPowerSupplyAttributes(
1709 sensorsAsyncResp, inventoryItems,
1710 std::move(callback));
1711 BMCWEB_LOG_DEBUG("getInventoryLedsCb exit");
1712 };
1713
1714 // Find led connections and get the data
1715 getInventoryLeds(sensorsAsyncResp, inventoryItems,
1716 std::move(getInventoryLedsCb));
1717 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb exit");
1718 };
1719
1720 // Get inventory item data from connections
1721 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1722 invConnections,
1723 std::move(getInventoryItemsDataCb));
1724 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001725 };
1726
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001727 // Get connections that provide inventory item data
1728 getInventoryItemsConnections(
1729 sensorsAsyncResp, inventoryItems,
1730 std::move(getInventoryItemsConnectionsCb));
1731 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001732 };
1733
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001734 // Get associations from sensors to inventory items
Ed Tanousd0090732022-10-04 17:22:56 -07001735 getInventoryItemAssociations(sensorsAsyncResp, sensorNames,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001736 std::move(getInventoryItemAssociationsCb));
Ed Tanous62598e32023-07-17 17:06:25 -07001737 BMCWEB_LOG_DEBUG("getInventoryItems exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001738}
1739
1740/**
1741 * @brief Returns JSON PowerSupply object for the specified inventory item.
1742 *
1743 * Searches for a JSON PowerSupply object that matches the specified inventory
1744 * item. If one is not found, a new PowerSupply object is added to the JSON
1745 * array.
1746 *
1747 * Multiple sensors are often associated with one power supply inventory item.
1748 * As a result, multiple sensor values are stored in one JSON PowerSupply
1749 * object.
1750 *
1751 * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1752 * @param inventoryItem Inventory item for the power supply.
1753 * @param chassisId Chassis that contains the power supply.
1754 * @return JSON PowerSupply object for the specified inventory item.
1755 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001756inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001757 const InventoryItem& inventoryItem,
1758 const std::string& chassisId)
1759{
Ed Tanous18f8f602023-07-18 10:07:23 -07001760 std::string nameS;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001761 nameS.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001762 std::ranges::replace_copy(inventoryItem.name, nameS.begin(), '_', ' ');
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001763 // Check if matching PowerSupply object already exists in JSON array
1764 for (nlohmann::json& powerSupply : powerSupplyArray)
1765 {
Ed Tanous18f8f602023-07-18 10:07:23 -07001766 nlohmann::json::iterator nameIt = powerSupply.find("Name");
1767 if (nameIt == powerSupply.end())
1768 {
1769 continue;
1770 }
1771 const std::string* name = nameIt->get_ptr<std::string*>();
1772 if (name == nullptr)
1773 {
1774 continue;
1775 }
1776 if (nameS == *name)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001777 {
1778 return powerSupply;
1779 }
1780 }
1781
1782 // Add new PowerSupply object to JSON array
1783 powerSupplyArray.push_back({});
1784 nlohmann::json& powerSupply = powerSupplyArray.back();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001785 boost::urls::url url =
1786 boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
Willy Tueddfc432022-09-26 16:46:38 +00001787 url.set_fragment(("/PowerSupplies"_json_pointer).to_string());
1788 powerSupply["@odata.id"] = std::move(url);
Ed Tanous18f8f602023-07-18 10:07:23 -07001789 std::string escaped;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001790 escaped.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001791 std::ranges::replace_copy(inventoryItem.name, escaped.begin(), '_', ' ');
1792 powerSupply["Name"] = std::move(escaped);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001793 powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1794 powerSupply["Model"] = inventoryItem.model;
1795 powerSupply["PartNumber"] = inventoryItem.partNumber;
1796 powerSupply["SerialNumber"] = inventoryItem.serialNumber;
Janet Adkinsc9563602024-08-28 11:37:46 -05001797 sensor_utils::setLedState(powerSupply, &inventoryItem);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001798
Gunnar Mills42cbe532019-08-15 15:26:54 -05001799 if (inventoryItem.powerSupplyEfficiencyPercent >= 0)
1800 {
1801 powerSupply["EfficiencyPercent"] =
1802 inventoryItem.powerSupplyEfficiencyPercent;
1803 }
1804
Janet Adkinsc9563602024-08-28 11:37:46 -05001805 powerSupply["Status"]["State"] =
1806 sensor_utils::getState(&inventoryItem, true);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001807 const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1808 powerSupply["Status"]["Health"] = health;
1809
1810 return powerSupply;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001811}
1812
1813/**
Shawn McCarneyde629b62019-03-08 10:42:51 -06001814 * @brief Gets the values of the specified sensors.
1815 *
1816 * Stores the results as JSON in the SensorsAsyncResp.
1817 *
1818 * Gets the sensor values asynchronously. Stores the results later when the
1819 * information has been obtained.
1820 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001821 * The sensorNames set contains all requested sensors for the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001822 *
1823 * To minimize the number of DBus calls, the DBus method
1824 * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1825 * values of all sensors provided by a connection (service).
1826 *
1827 * The connections set contains all the connections that provide sensor values.
1828 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001829 * The InventoryItem vector contains D-Bus inventory items associated with the
1830 * sensors. Inventory item data is needed for some Redfish sensor properties.
1831 *
Shawn McCarneyde629b62019-03-08 10:42:51 -06001832 * @param SensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001833 * @param sensorNames All requested sensors within the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001834 * @param connections Connections that provide sensor values.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001835 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001836 * @param inventoryItems Inventory items associated with the sensors.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001837 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001838inline void getSensorData(
Ed Tanous81ce6092020-12-17 16:54:55 +00001839 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001840 const std::shared_ptr<std::set<std::string>>& sensorNames,
1841 const std::set<std::string>& connections,
Ed Tanousb5a76932020-09-29 16:16:58 -07001842 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001843{
Ed Tanous62598e32023-07-17 17:06:25 -07001844 BMCWEB_LOG_DEBUG("getSensorData enter");
Shawn McCarneyde629b62019-03-08 10:42:51 -06001845 // Get managed objects from all services exposing sensors
1846 for (const std::string& connection : connections)
1847 {
George Liu5eb468d2023-06-20 17:03:24 +08001848 sdbusplus::message::object_path sensorPath(
1849 "/xyz/openbmc_project/sensors");
1850 dbus::utility::getManagedObjects(
1851 connection, sensorPath,
Ed Tanous002d39b2022-05-31 08:59:27 -07001852 [sensorsAsyncResp, sensorNames,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001853 inventoryItems](const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -07001854 const dbus::utility::ManagedObjectType& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001855 BMCWEB_LOG_DEBUG("getManagedObjectsCb enter");
1856 if (ec)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001857 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001858 BMCWEB_LOG_ERROR("getManagedObjectsCb DBUS error: {}", ec);
1859 messages::internalError(sensorsAsyncResp->asyncResp->res);
1860 return;
1861 }
Janet Adkins0c728b42024-08-29 11:09:10 -05001862 auto chassisSubNode = sensor_utils::chassisSubNodeFromString(
1863 sensorsAsyncResp->chassisSubNode);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001864 // Go through all objects and update response with sensor data
1865 for (const auto& objDictEntry : resp)
1866 {
1867 const std::string& objPath =
1868 static_cast<const std::string&>(objDictEntry.first);
1869 BMCWEB_LOG_DEBUG("getManagedObjectsCb parsing object {}",
Ed Tanous62598e32023-07-17 17:06:25 -07001870 objPath);
Shawn McCarneyde629b62019-03-08 10:42:51 -06001871
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001872 std::vector<std::string> split;
1873 // Reserve space for
1874 // /xyz/openbmc_project/sensors/<name>/<subname>
1875 split.reserve(6);
1876 // NOLINTNEXTLINE
1877 bmcweb::split(split, objPath, '/');
1878 if (split.size() < 6)
Nan Zhou928fefb2022-03-28 08:45:00 -07001879 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001880 BMCWEB_LOG_ERROR("Got path that isn't long enough {}",
1881 objPath);
1882 continue;
Nan Zhou928fefb2022-03-28 08:45:00 -07001883 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001884 // These indexes aren't intuitive, as split puts an empty
1885 // string at the beginning
1886 const std::string& sensorType = split[4];
1887 const std::string& sensorName = split[5];
1888 BMCWEB_LOG_DEBUG("sensorName {} sensorType {}", sensorName,
1889 sensorType);
1890 if (sensorNames->find(objPath) == sensorNames->end())
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001891 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001892 BMCWEB_LOG_DEBUG("{} not in sensor list ", sensorName);
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001893 continue;
1894 }
1895
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001896 // Find inventory item (if any) associated with sensor
1897 InventoryItem* inventoryItem =
1898 findInventoryItemForSensor(inventoryItems, objPath);
1899
1900 const std::string& sensorSchema =
1901 sensorsAsyncResp->chassisSubNode;
1902
1903 nlohmann::json* sensorJson = nullptr;
1904
Janet Adkins0c728b42024-08-29 11:09:10 -05001905 if (sensorSchema == sensors::sensorsNodeStr &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001906 !sensorsAsyncResp->efficientExpand)
Nan Zhou928fefb2022-03-28 08:45:00 -07001907 {
Janet Adkins1516c212024-08-14 13:22:41 -05001908 std::string sensorId =
1909 redfish::sensor_utils::getSensorId(sensorName,
1910 sensorType);
Ed Tanous677bb752022-09-15 10:52:19 -07001911
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001912 sensorsAsyncResp->asyncResp->res
1913 .jsonValue["@odata.id"] = boost::urls::format(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001914 "/redfish/v1/Chassis/{}/{}/{}",
Ed Tanous677bb752022-09-15 10:52:19 -07001915 sensorsAsyncResp->chassisId,
1916 sensorsAsyncResp->chassisSubNode, sensorId);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001917 sensorJson =
1918 &(sensorsAsyncResp->asyncResp->res.jsonValue);
Nan Zhou928fefb2022-03-28 08:45:00 -07001919 }
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001920 else
1921 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001922 std::string fieldName;
1923 if (sensorsAsyncResp->efficientExpand)
1924 {
1925 fieldName = "Members";
1926 }
1927 else if (sensorType == "temperature")
1928 {
1929 fieldName = "Temperatures";
1930 }
1931 else if (sensorType == "fan" ||
1932 sensorType == "fan_tach" ||
1933 sensorType == "fan_pwm")
1934 {
1935 fieldName = "Fans";
1936 }
1937 else if (sensorType == "voltage")
1938 {
1939 fieldName = "Voltages";
1940 }
1941 else if (sensorType == "power")
1942 {
1943 if (sensorName == "total_power")
1944 {
1945 fieldName = "PowerControl";
1946 }
1947 else if ((inventoryItem != nullptr) &&
1948 (inventoryItem->isPowerSupply))
1949 {
1950 fieldName = "PowerSupplies";
1951 }
1952 else
1953 {
1954 // Other power sensors are in SensorCollection
1955 continue;
1956 }
1957 }
1958 else
1959 {
1960 BMCWEB_LOG_ERROR(
1961 "Unsure how to handle sensorType {}",
1962 sensorType);
1963 continue;
1964 }
1965
1966 nlohmann::json& tempArray =
1967 sensorsAsyncResp->asyncResp->res
1968 .jsonValue[fieldName];
1969 if (fieldName == "PowerControl")
1970 {
1971 if (tempArray.empty())
1972 {
1973 // Put multiple "sensors" into a single
1974 // PowerControl. Follows MemberId naming and
1975 // naming in power.hpp.
1976 nlohmann::json::object_t power;
1977 boost::urls::url url = boost::urls::format(
1978 "/redfish/v1/Chassis/{}/{}",
1979 sensorsAsyncResp->chassisId,
1980 sensorsAsyncResp->chassisSubNode);
1981 url.set_fragment(
1982 (""_json_pointer / fieldName / "0")
1983 .to_string());
1984 power["@odata.id"] = std::move(url);
1985 tempArray.emplace_back(std::move(power));
1986 }
1987 sensorJson = &(tempArray.back());
1988 }
1989 else if (fieldName == "PowerSupplies")
1990 {
1991 if (inventoryItem != nullptr)
1992 {
1993 sensorJson = &(getPowerSupply(
1994 tempArray, *inventoryItem,
1995 sensorsAsyncResp->chassisId));
1996 }
1997 }
1998 else if (fieldName == "Members")
1999 {
Janet Adkins1516c212024-08-14 13:22:41 -05002000 std::string sensorId =
2001 redfish::sensor_utils::getSensorId(sensorName,
2002 sensorType);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002003
2004 nlohmann::json::object_t member;
2005 member["@odata.id"] = boost::urls::format(
2006 "/redfish/v1/Chassis/{}/{}/{}",
2007 sensorsAsyncResp->chassisId,
2008 sensorsAsyncResp->chassisSubNode, sensorId);
2009 tempArray.emplace_back(std::move(member));
2010 sensorJson = &(tempArray.back());
2011 }
2012 else
2013 {
2014 nlohmann::json::object_t member;
2015 boost::urls::url url = boost::urls::format(
2016 "/redfish/v1/Chassis/{}/{}",
2017 sensorsAsyncResp->chassisId,
2018 sensorsAsyncResp->chassisSubNode);
2019 url.set_fragment(
2020 (""_json_pointer / fieldName).to_string());
2021 member["@odata.id"] = std::move(url);
2022 tempArray.emplace_back(std::move(member));
2023 sensorJson = &(tempArray.back());
2024 }
2025 }
2026
2027 if (sensorJson != nullptr)
2028 {
Janet Adkins0c728b42024-08-29 11:09:10 -05002029 objectInterfacesToJson(
2030 sensorName, sensorType, chassisSubNode,
2031 objDictEntry.second, *sensorJson, inventoryItem);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002032
2033 std::string path = "/xyz/openbmc_project/sensors/";
2034 path += sensorType;
2035 path += "/";
2036 path += sensorName;
2037 sensorsAsyncResp->addMetadata(*sensorJson, path);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002038 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002039 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002040 if (sensorsAsyncResp.use_count() == 1)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002041 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002042 sortJSONResponse(sensorsAsyncResp);
Janet Adkins0c728b42024-08-29 11:09:10 -05002043 if (chassisSubNode ==
2044 sensor_utils::ChassisSubNode::sensorsNode &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002045 sensorsAsyncResp->efficientExpand)
2046 {
2047 sensorsAsyncResp->asyncResp->res
2048 .jsonValue["Members@odata.count"] =
2049 sensorsAsyncResp->asyncResp->res
2050 .jsonValue["Members"]
2051 .size();
2052 }
Janet Adkins0c728b42024-08-29 11:09:10 -05002053 else if (chassisSubNode ==
2054 sensor_utils::ChassisSubNode::thermalNode)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002055 {
2056 populateFanRedundancy(sensorsAsyncResp);
2057 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002058 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002059 BMCWEB_LOG_DEBUG("getManagedObjectsCb exit");
2060 });
Ed Tanous23a21a12020-07-25 04:45:05 +00002061 }
Ed Tanous62598e32023-07-17 17:06:25 -07002062 BMCWEB_LOG_DEBUG("getSensorData exit");
Shawn McCarneyde629b62019-03-08 10:42:51 -06002063}
2064
Nan Zhoufe04d492022-06-22 17:10:41 +00002065inline void
2066 processSensorList(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
2067 const std::shared_ptr<std::set<std::string>>& sensorNames)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002068{
Nan Zhoufe04d492022-06-22 17:10:41 +00002069 auto getConnectionCb = [sensorsAsyncResp, sensorNames](
2070 const std::set<std::string>& connections) {
Ed Tanous62598e32023-07-17 17:06:25 -07002071 BMCWEB_LOG_DEBUG("getConnectionCb enter");
Ed Tanousd0090732022-10-04 17:22:56 -07002072 auto getInventoryItemsCb =
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002073 [sensorsAsyncResp, sensorNames, connections](
2074 const std::shared_ptr<std::vector<InventoryItem>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07002075 inventoryItems) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002076 BMCWEB_LOG_DEBUG("getInventoryItemsCb enter");
2077 // Get sensor data and store results in JSON
2078 getSensorData(sensorsAsyncResp, sensorNames, connections,
2079 inventoryItems);
2080 BMCWEB_LOG_DEBUG("getInventoryItemsCb exit");
2081 };
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002082
Ed Tanousd0090732022-10-04 17:22:56 -07002083 // Get inventory items associated with sensors
2084 getInventoryItems(sensorsAsyncResp, sensorNames,
2085 std::move(getInventoryItemsCb));
2086
Ed Tanous62598e32023-07-17 17:06:25 -07002087 BMCWEB_LOG_DEBUG("getConnectionCb exit");
Ed Tanous002d39b2022-05-31 08:59:27 -07002088 };
2089
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002090 // Get set of connections that provide sensor values
Ed Tanous81ce6092020-12-17 16:54:55 +00002091 getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002092}
2093
Shawn McCarneyde629b62019-03-08 10:42:51 -06002094/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002095 * @brief Entry point for retrieving sensors data related to requested
2096 * chassis.
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02002097 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002098 */
Ed Tanousb5a76932020-09-29 16:16:58 -07002099inline void
Ed Tanous81ce6092020-12-17 16:54:55 +00002100 getChassisData(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002101{
Ed Tanous62598e32023-07-17 17:06:25 -07002102 BMCWEB_LOG_DEBUG("getChassisData enter");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002103 auto getChassisCb =
Ed Tanous81ce6092020-12-17 16:54:55 +00002104 [sensorsAsyncResp](
Nan Zhoufe04d492022-06-22 17:10:41 +00002105 const std::shared_ptr<std::set<std::string>>& sensorNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002106 BMCWEB_LOG_DEBUG("getChassisCb enter");
2107 processSensorList(sensorsAsyncResp, sensorNames);
2108 BMCWEB_LOG_DEBUG("getChassisCb exit");
2109 };
Nan Zhou928fefb2022-03-28 08:45:00 -07002110 // SensorCollection doesn't contain the Redundancy property
Janet Adkins0c728b42024-08-29 11:09:10 -05002111 if (sensorsAsyncResp->chassisSubNode != sensors::sensorsNodeStr)
Nan Zhou928fefb2022-03-28 08:45:00 -07002112 {
2113 sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
2114 nlohmann::json::array();
2115 }
Shawn McCarney26f03892019-05-03 13:20:24 -05002116 // Get set of sensors in chassis
Ed Tanous7f1cc262022-08-09 13:33:57 -07002117 getChassis(sensorsAsyncResp->asyncResp, sensorsAsyncResp->chassisId,
2118 sensorsAsyncResp->chassisSubNode, sensorsAsyncResp->types,
2119 std::move(getChassisCb));
Ed Tanous62598e32023-07-17 17:06:25 -07002120 BMCWEB_LOG_DEBUG("getChassisData exit");
Ed Tanous271584a2019-07-09 16:24:22 -07002121}
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002122
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302123/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002124 * @brief Find the requested sensorName in the list of all sensors supplied by
2125 * the chassis node
2126 *
2127 * @param sensorName The sensor name supplied in the PATCH request
2128 * @param sensorsList The list of sensors managed by the chassis node
2129 * @param sensorsModified The list of sensors that were found as a result of
2130 * repeated calls to this function
2131 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002132inline bool findSensorNameUsingSensorPath(
2133 std::string_view sensorName, const std::set<std::string>& sensorsList,
2134 std::set<std::string>& sensorsModified)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002135{
Nan Zhoufe04d492022-06-22 17:10:41 +00002136 for (const auto& chassisSensor : sensorsList)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002137 {
George Liu28aa8de2021-02-01 15:13:30 +08002138 sdbusplus::message::object_path path(chassisSensor);
Ed Tanousb00dcc22021-02-23 12:52:50 -08002139 std::string thisSensorName = path.filename();
George Liu28aa8de2021-02-01 15:13:30 +08002140 if (thisSensorName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002141 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002142 continue;
2143 }
2144 if (thisSensorName == sensorName)
2145 {
2146 sensorsModified.emplace(chassisSensor);
2147 return true;
2148 }
2149 }
2150 return false;
2151}
2152
2153/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302154 * @brief Entry point for overriding sensor values of given sensor
2155 *
zhanghch058d1b46d2021-04-01 11:18:24 +08002156 * @param sensorAsyncResp response object
Carol Wang4bb3dc32019-10-17 18:15:02 +08002157 * @param allCollections Collections extract from sensors' request patch info
jayaprakash Mutyala91e130a2020-03-04 22:26:38 +00002158 * @param chassisSubNode Chassis Node for which the query has to happen
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302159 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002160inline void setSensorsOverride(
Ed Tanousb5a76932020-09-29 16:16:58 -07002161 const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
Ed Tanous08850572024-03-06 15:09:17 -08002162 std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>&
jayaprakash Mutyala397fd612020-02-06 23:33:34 +00002163 allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302164{
Ed Tanous62598e32023-07-17 17:06:25 -07002165 BMCWEB_LOG_INFO("setSensorsOverride for subNode{}",
2166 sensorAsyncResp->chassisSubNode);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302167
Ed Tanousd02aad32024-02-13 14:43:34 -08002168 std::string_view propertyValueName;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302169 std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302170 std::string memberId;
Ed Tanous543f4402022-01-06 13:12:53 -08002171 double value = 0.0;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302172 for (auto& collectionItems : allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302173 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302174 if (collectionItems.first == "Temperatures")
2175 {
2176 propertyValueName = "ReadingCelsius";
2177 }
2178 else if (collectionItems.first == "Fans")
2179 {
2180 propertyValueName = "Reading";
2181 }
2182 else
2183 {
2184 propertyValueName = "ReadingVolts";
2185 }
2186 for (auto& item : collectionItems.second)
2187 {
Ed Tanous08850572024-03-06 15:09:17 -08002188 if (!json_util::readJsonObject(
2189 item, sensorAsyncResp->asyncResp->res, "MemberId", memberId,
2190 propertyValueName, value))
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302191 {
2192 return;
2193 }
2194 overrideMap.emplace(memberId,
2195 std::make_pair(value, collectionItems.first));
2196 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302197 }
Carol Wang4bb3dc32019-10-17 18:15:02 +08002198
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002199 auto getChassisSensorListCb = [sensorAsyncResp, overrideMap,
2200 propertyValueNameStr =
2201 std::string(propertyValueName)](
2202 const std::shared_ptr<
2203 std::set<std::string>>& sensorsList) {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002204 // Match sensor names in the PATCH request to those managed by the
2205 // chassis node
Nan Zhoufe04d492022-06-22 17:10:41 +00002206 const std::shared_ptr<std::set<std::string>> sensorNames =
2207 std::make_shared<std::set<std::string>>();
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302208 for (const auto& item : overrideMap)
2209 {
2210 const auto& sensor = item.first;
Ed Tanousc71d6122022-11-29 14:10:32 -08002211 std::pair<std::string, std::string> sensorNameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002212 redfish::sensor_utils::splitSensorNameAndType(sensor);
Ed Tanousc71d6122022-11-29 14:10:32 -08002213 if (!findSensorNameUsingSensorPath(sensorNameType.second,
2214 *sensorsList, *sensorNames))
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302215 {
Ed Tanous62598e32023-07-17 17:06:25 -07002216 BMCWEB_LOG_INFO("Unable to find memberId {}", item.first);
zhanghch058d1b46d2021-04-01 11:18:24 +08002217 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302218 item.second.second, item.first);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302219 return;
2220 }
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302221 }
2222 // Get the connection to which the memberId belongs
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002223 auto getObjectsWithConnectionCb = [sensorAsyncResp, overrideMap,
2224 propertyValueNameStr](
2225 const std::set<
2226 std::string>& /*connections*/,
2227 const std::set<std::pair<
2228 std::string, std::string>>&
2229 objectsWithConnection) {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002230 if (objectsWithConnection.size() != overrideMap.size())
2231 {
Ed Tanous62598e32023-07-17 17:06:25 -07002232 BMCWEB_LOG_INFO(
2233 "Unable to find all objects with proper connection {} requested {}",
2234 objectsWithConnection.size(), overrideMap.size());
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002235 messages::resourceNotFound(
2236 sensorAsyncResp->asyncResp->res,
Janet Adkins0c728b42024-08-29 11:09:10 -05002237 sensorAsyncResp->chassisSubNode == sensors::thermalNodeStr
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002238 ? "Temperatures"
2239 : "Voltages",
2240 "Count");
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002241 return;
2242 }
2243 for (const auto& item : objectsWithConnection)
2244 {
2245 sdbusplus::message::object_path path(item.first);
2246 std::string sensorName = path.filename();
2247 if (sensorName.empty())
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302248 {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002249 messages::internalError(sensorAsyncResp->asyncResp->res);
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302250 return;
2251 }
Janet Adkins1516c212024-08-14 13:22:41 -05002252 std::string id = redfish::sensor_utils::getSensorId(
2253 sensorName, path.parent_path().filename());
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302254
Ban Feng3f5eb752023-06-29 09:19:20 +08002255 const auto& iterator = overrideMap.find(id);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002256 if (iterator == overrideMap.end())
2257 {
Ed Tanous62598e32023-07-17 17:06:25 -07002258 BMCWEB_LOG_INFO("Unable to find sensor object{}",
2259 item.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002260 messages::internalError(sensorAsyncResp->asyncResp->res);
2261 return;
2262 }
Ginu Georgee93abac2024-06-14 17:35:27 +05302263 setDbusProperty(sensorAsyncResp->asyncResp,
2264 propertyValueNameStr, item.second, item.first,
2265 "xyz.openbmc_project.Sensor.Value", "Value",
Ed Tanousd02aad32024-02-13 14:43:34 -08002266 iterator->second.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002267 }
2268 };
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302269 // Get object with connection for the given sensor name
2270 getObjectsWithConnection(sensorAsyncResp, sensorNames,
2271 std::move(getObjectsWithConnectionCb));
2272 };
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302273 // get full sensor list for the given chassisId and cross verify the sensor.
Ed Tanous7f1cc262022-08-09 13:33:57 -07002274 getChassis(sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId,
2275 sensorAsyncResp->chassisSubNode, sensorAsyncResp->types,
2276 std::move(getChassisSensorListCb));
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302277}
2278
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002279/**
2280 * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus
2281 * path of the sensor.
2282 *
2283 * Function builds valid Redfish response for sensor query of given chassis and
2284 * node. It then builds metadata about Redfish<->D-Bus correlations and provides
2285 * it to caller in a callback.
2286 *
2287 * @param chassis Chassis for which retrieval should be performed
Janet Adkinsc9563602024-08-28 11:37:46 -05002288 * @param node Node (group) of sensors. See sensor_utils::node for supported
2289 * values
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002290 * @param mapComplete Callback to be called with retrieval result
2291 */
Ed Tanous931edc72023-11-01 12:09:07 -07002292template <typename Callback>
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002293inline void retrieveUriToDbusMap(
2294 const std::string& chassis, const std::string& node, Callback&& mapComplete)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002295{
Ed Tanous02da7c52022-02-27 00:09:02 -08002296 decltype(sensors::paths)::const_iterator pathIt =
2297 std::find_if(sensors::paths.cbegin(), sensors::paths.cend(),
2298 [&node](auto&& val) { return val.first == node; });
2299 if (pathIt == sensors::paths.cend())
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002300 {
Ed Tanous62598e32023-07-17 17:06:25 -07002301 BMCWEB_LOG_ERROR("Wrong node provided : {}", node);
Ed Tanous6804b5c2023-10-31 14:50:03 -07002302 std::map<std::string, std::string> noop;
2303 mapComplete(boost::beast::http::status::bad_request, noop);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002304 return;
2305 }
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002306
Nan Zhou72374eb2022-01-27 17:06:51 -08002307 auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002308 auto callback =
2309 [asyncResp, mapCompleteCb = std::forward<Callback>(mapComplete)](
2310 const boost::beast::http::status status,
2311 const std::map<std::string, std::string>& uriToDbus) {
2312 mapCompleteCb(status, uriToDbus);
2313 };
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002314
2315 auto resp = std::make_shared<SensorsAsyncResp>(
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002316 asyncResp, chassis, pathIt->second, node, std::move(callback));
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002317 getChassisData(resp);
2318}
2319
Nan Zhoubacb2162022-04-06 11:28:32 -07002320namespace sensors
2321{
Nan Zhou928fefb2022-03-28 08:45:00 -07002322
Nan Zhoubacb2162022-04-06 11:28:32 -07002323inline void getChassisCallback(
Ed Tanousc1d019a2022-08-06 09:36:06 -07002324 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2325 std::string_view chassisId, std::string_view chassisSubNode,
Nan Zhoufe04d492022-06-22 17:10:41 +00002326 const std::shared_ptr<std::set<std::string>>& sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002327{
Ed Tanous62598e32023-07-17 17:06:25 -07002328 BMCWEB_LOG_DEBUG("getChassisCallback enter ");
Nan Zhoubacb2162022-04-06 11:28:32 -07002329
Ed Tanousc1d019a2022-08-06 09:36:06 -07002330 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
2331 for (const std::string& sensor : *sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002332 {
Ed Tanous62598e32023-07-17 17:06:25 -07002333 BMCWEB_LOG_DEBUG("Adding sensor: {}", sensor);
Nan Zhoubacb2162022-04-06 11:28:32 -07002334
2335 sdbusplus::message::object_path path(sensor);
2336 std::string sensorName = path.filename();
2337 if (sensorName.empty())
2338 {
Ed Tanous62598e32023-07-17 17:06:25 -07002339 BMCWEB_LOG_ERROR("Invalid sensor path: {}", sensor);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002340 messages::internalError(asyncResp->res);
Nan Zhoubacb2162022-04-06 11:28:32 -07002341 return;
2342 }
Ed Tanousc1d019a2022-08-06 09:36:06 -07002343 std::string type = path.parent_path().filename();
Janet Adkins1516c212024-08-14 13:22:41 -05002344 std::string id = redfish::sensor_utils::getSensorId(sensorName, type);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002345
Ed Tanous14766872022-03-15 10:44:42 -07002346 nlohmann::json::object_t member;
Ed Tanousef4c65b2023-04-24 15:28:50 -07002347 member["@odata.id"] = boost::urls::format(
2348 "/redfish/v1/Chassis/{}/{}/{}", chassisId, chassisSubNode, id);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002349
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002350 entriesArray.emplace_back(std::move(member));
Nan Zhoubacb2162022-04-06 11:28:32 -07002351 }
2352
Ed Tanousc1d019a2022-08-06 09:36:06 -07002353 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Ed Tanous62598e32023-07-17 17:06:25 -07002354 BMCWEB_LOG_DEBUG("getChassisCallback exit");
Nan Zhoubacb2162022-04-06 11:28:32 -07002355}
Nan Zhoue6bd8462022-06-01 04:35:35 +00002356
Ed Tanousac106bf2023-06-07 09:24:59 -07002357inline void handleSensorCollectionGet(
2358 App& app, const crow::Request& req,
2359 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2360 const std::string& chassisId)
Nan Zhoude167a62022-06-01 04:47:45 +00002361{
2362 query_param::QueryCapabilities capabilities = {
2363 .canDelegateExpandLevel = 1,
2364 };
2365 query_param::Query delegatedQuery;
Ed Tanousac106bf2023-06-07 09:24:59 -07002366 if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
Nan Zhoude167a62022-06-01 04:47:45 +00002367 delegatedQuery, capabilities))
2368 {
2369 return;
2370 }
2371
2372 if (delegatedQuery.expandType != query_param::ExpandType::None)
2373 {
2374 // we perform efficient expand.
Ed Tanousac106bf2023-06-07 09:24:59 -07002375 auto sensorsAsyncResp = std::make_shared<SensorsAsyncResp>(
2376 asyncResp, chassisId, sensors::dbus::sensorPaths,
Janet Adkins0c728b42024-08-29 11:09:10 -05002377 sensors::sensorsNodeStr,
Nan Zhoude167a62022-06-01 04:47:45 +00002378 /*efficientExpand=*/true);
Ed Tanousac106bf2023-06-07 09:24:59 -07002379 getChassisData(sensorsAsyncResp);
Nan Zhoude167a62022-06-01 04:47:45 +00002380
Ed Tanous62598e32023-07-17 17:06:25 -07002381 BMCWEB_LOG_DEBUG(
2382 "SensorCollection doGet exit via efficient expand handler");
Nan Zhoude167a62022-06-01 04:47:45 +00002383 return;
Ed Tanous0bad3202022-06-02 13:53:59 -07002384 }
Nan Zhoude167a62022-06-01 04:47:45 +00002385
Nan Zhoude167a62022-06-01 04:47:45 +00002386 // We get all sensors as hyperlinkes in the chassis (this
2387 // implies we reply on the default query parameters handler)
Janet Adkins0c728b42024-08-29 11:09:10 -05002388 getChassis(asyncResp, chassisId, sensors::sensorsNodeStr, dbus::sensorPaths,
Ed Tanousac106bf2023-06-07 09:24:59 -07002389 std::bind_front(sensors::getChassisCallback, asyncResp,
Janet Adkins0c728b42024-08-29 11:09:10 -05002390 chassisId, sensors::sensorsNodeStr));
Ed Tanousc1d019a2022-08-06 09:36:06 -07002391}
Ed Tanous7f1cc262022-08-09 13:33:57 -07002392
Ed Tanousc1d019a2022-08-06 09:36:06 -07002393inline void
2394 getSensorFromDbus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2395 const std::string& sensorPath,
2396 const ::dbus::utility::MapperGetObject& mapperResponse)
2397{
2398 if (mapperResponse.size() != 1)
2399 {
2400 messages::internalError(asyncResp->res);
2401 return;
2402 }
2403 const auto& valueIface = *mapperResponse.begin();
2404 const std::string& connectionName = valueIface.first;
Ed Tanous62598e32023-07-17 17:06:25 -07002405 BMCWEB_LOG_DEBUG("Looking up {}", connectionName);
2406 BMCWEB_LOG_DEBUG("Path {}", sensorPath);
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +02002407
2408 sdbusplus::asio::getAllProperties(
2409 *crow::connections::systemBus, connectionName, sensorPath, "",
Ed Tanousc1d019a2022-08-06 09:36:06 -07002410 [asyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002411 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002412 const ::dbus::utility::DBusPropertiesMap& valuesDict) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002413 if (ec)
2414 {
2415 messages::internalError(asyncResp->res);
2416 return;
2417 }
2418 sdbusplus::message::object_path path(sensorPath);
2419 std::string name = path.filename();
2420 path = path.parent_path();
2421 std::string type = path.filename();
Janet Adkinsc9563602024-08-28 11:37:46 -05002422 sensor_utils::objectPropertiesToJson(
Janet Adkins0c728b42024-08-29 11:09:10 -05002423 name, type, sensor_utils::ChassisSubNode::sensorsNode,
2424 valuesDict, asyncResp->res.jsonValue, nullptr);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002425 });
Nan Zhoude167a62022-06-01 04:47:45 +00002426}
2427
Nan Zhoue6bd8462022-06-01 04:35:35 +00002428inline void handleSensorGet(App& app, const crow::Request& req,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002429 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous677bb752022-09-15 10:52:19 -07002430 const std::string& chassisId,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002431 const std::string& sensorId)
Nan Zhoue6bd8462022-06-01 04:35:35 +00002432{
Ed Tanousc1d019a2022-08-06 09:36:06 -07002433 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Nan Zhoue6bd8462022-06-01 04:35:35 +00002434 {
2435 return;
2436 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002437 std::pair<std::string, std::string> nameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002438 redfish::sensor_utils::splitSensorNameAndType(sensorId);
Ed Tanousc71d6122022-11-29 14:10:32 -08002439 if (nameType.first.empty() || nameType.second.empty())
Ed Tanousc1d019a2022-08-06 09:36:06 -07002440 {
2441 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2442 return;
2443 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002444
Ed Tanousef4c65b2023-04-24 15:28:50 -07002445 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2446 "/redfish/v1/Chassis/{}/Sensors/{}", chassisId, sensorId);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002447
Ed Tanous62598e32023-07-17 17:06:25 -07002448 BMCWEB_LOG_DEBUG("Sensor doGet enter");
Nan Zhoue6bd8462022-06-01 04:35:35 +00002449
George Liu2b731192023-01-11 16:27:13 +08002450 constexpr std::array<std::string_view, 1> interfaces = {
Nan Zhoue6bd8462022-06-01 04:35:35 +00002451 "xyz.openbmc_project.Sensor.Value"};
Ed Tanousc71d6122022-11-29 14:10:32 -08002452 std::string sensorPath = "/xyz/openbmc_project/sensors/" + nameType.first +
2453 '/' + nameType.second;
Nan Zhoue6bd8462022-06-01 04:35:35 +00002454 // Get a list of all of the sensors that implement Sensor.Value
2455 // and get the path and service name associated with the sensor
George Liu2b731192023-01-11 16:27:13 +08002456 ::dbus::utility::getDbusObject(
2457 sensorPath, interfaces,
Myung Baeaec0ec32023-05-31 15:10:01 -05002458 [asyncResp, sensorId,
George Liu2b731192023-01-11 16:27:13 +08002459 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002460 const ::dbus::utility::MapperGetObject& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002461 BMCWEB_LOG_DEBUG("respHandler1 enter");
2462 if (ec == boost::system::errc::io_error)
2463 {
2464 BMCWEB_LOG_WARNING("Sensor not found from getSensorPaths");
2465 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2466 return;
2467 }
2468 if (ec)
2469 {
2470 messages::internalError(asyncResp->res);
2471 BMCWEB_LOG_ERROR(
2472 "Sensor getSensorPaths resp_handler: Dbus error {}", ec);
2473 return;
2474 }
2475 getSensorFromDbus(asyncResp, sensorPath, subtree);
2476 BMCWEB_LOG_DEBUG("respHandler1 exit");
2477 });
Nan Zhoue6bd8462022-06-01 04:35:35 +00002478}
2479
Nan Zhoubacb2162022-04-06 11:28:32 -07002480} // namespace sensors
2481
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002482inline void requestRoutesSensorCollection(App& app)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002483{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002484 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
Ed Tanoused398212021-06-09 17:05:54 -07002485 .privileges(redfish::privileges::getSensorCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002486 .methods(boost::beast::http::verb::get)(
Nan Zhoude167a62022-06-01 04:47:45 +00002487 std::bind_front(sensors::handleSensorCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002488}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002489
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002490inline void requestRoutesSensor(App& app)
2491{
2492 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002493 .privileges(redfish::privileges::getSensor)
Ed Tanous002d39b2022-05-31 08:59:27 -07002494 .methods(boost::beast::http::verb::get)(
Nan Zhoue6bd8462022-06-01 04:35:35 +00002495 std::bind_front(sensors::handleSensorGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002496}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002497
Ed Tanous1abe55e2018-09-05 08:30:59 -07002498} // namespace redfish