blob: a02eb60b918ade0e87ff0c2ecfdcf1765ed9cbd7 [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);
712 if (entry != response.end())
713 {
714 std::sort(entry->begin(), entry->end(),
Ed Tanous02cad962022-06-30 16:50:15 -0700715 [](const nlohmann::json& c1, const nlohmann::json& c2) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400716 return c1["Name"] < c2["Name"];
717 });
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700718
719 // add the index counts to the end of each entry
720 size_t count = 0;
721 for (nlohmann::json& sensorJson : *entry)
722 {
723 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
724 if (odata == sensorJson.end())
725 {
726 continue;
727 }
728 std::string* value = odata->get_ptr<std::string*>();
729 if (value != nullptr)
730 {
Willy Tueddfc432022-09-26 16:46:38 +0000731 *value += "/" + std::to_string(count);
George Liu3e35c762023-03-08 16:56:38 +0800732 sensorJson["MemberId"] = std::to_string(count);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700733 count++;
Ed Tanous81ce6092020-12-17 16:54:55 +0000734 sensorsAsyncResp->updateUri(sensorJson["Name"], *value);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700735 }
736 }
737 }
738 }
739}
740
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100741/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500742 * @brief Finds the inventory item with the specified object path.
743 * @param inventoryItems D-Bus inventory items associated with sensors.
744 * @param invItemObjPath D-Bus object path of inventory item.
745 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500746 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000747inline InventoryItem* findInventoryItem(
Ed Tanousb5a76932020-09-29 16:16:58 -0700748 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500749 const std::string& invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500750{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500751 for (InventoryItem& inventoryItem : *inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500752 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500753 if (inventoryItem.objectPath == invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500754 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500755 return &inventoryItem;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500756 }
757 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500758 return nullptr;
759}
760
761/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500762 * @brief Finds the inventory item associated with the specified sensor.
763 * @param inventoryItems D-Bus inventory items associated with sensors.
764 * @param sensorObjPath D-Bus object path of sensor.
765 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500766 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000767inline InventoryItem* findInventoryItemForSensor(
Ed Tanousb5a76932020-09-29 16:16:58 -0700768 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500769 const std::string& sensorObjPath)
770{
771 for (InventoryItem& inventoryItem : *inventoryItems)
772 {
Ed Tanousdb0d36e2023-06-30 10:37:05 -0700773 if (inventoryItem.sensors.contains(sensorObjPath))
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500774 {
775 return &inventoryItem;
776 }
777 }
778 return nullptr;
779}
780
781/**
Anthony Wilsond5005492019-07-31 16:34:17 -0500782 * @brief Finds the inventory item associated with the specified led path.
783 * @param inventoryItems D-Bus inventory items associated with sensors.
784 * @param ledObjPath D-Bus object path of led.
785 * @return Inventory item within vector, or nullptr if no match found.
786 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400787inline InventoryItem* findInventoryItemForLed(
788 std::vector<InventoryItem>& inventoryItems, const std::string& ledObjPath)
Anthony Wilsond5005492019-07-31 16:34:17 -0500789{
790 for (InventoryItem& inventoryItem : inventoryItems)
791 {
792 if (inventoryItem.ledObjectPath == ledObjPath)
793 {
794 return &inventoryItem;
795 }
796 }
797 return nullptr;
798}
799
800/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500801 * @brief Adds inventory item and associated sensor to specified vector.
802 *
803 * Adds a new InventoryItem to the vector if necessary. Searches for an
804 * existing InventoryItem with the specified object path. If not found, one is
805 * added to the vector.
806 *
807 * Next, the specified sensor is added to the set of sensors associated with the
808 * InventoryItem.
809 *
810 * @param inventoryItems D-Bus inventory items associated with sensors.
811 * @param invItemObjPath D-Bus object path of inventory item.
812 * @param sensorObjPath D-Bus object path of sensor
813 */
Ed Tanousb5a76932020-09-29 16:16:58 -0700814inline void addInventoryItem(
815 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
816 const std::string& invItemObjPath, const std::string& sensorObjPath)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500817{
818 // Look for inventory item in vector
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400819 InventoryItem* inventoryItem =
820 findInventoryItem(inventoryItems, invItemObjPath);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500821
822 // If inventory item doesn't exist in vector, add it
823 if (inventoryItem == nullptr)
824 {
825 inventoryItems->emplace_back(invItemObjPath);
826 inventoryItem = &(inventoryItems->back());
827 }
828
829 // Add sensor to set of sensors associated with inventory item
830 inventoryItem->sensors.emplace(sensorObjPath);
831}
832
833/**
834 * @brief Stores D-Bus data in the specified inventory item.
835 *
836 * Finds D-Bus data in the specified map of interfaces. Stores the data in the
837 * specified InventoryItem.
838 *
839 * This data is later used to provide sensor property values in the JSON
840 * response.
841 *
842 * @param inventoryItem Inventory item where data will be stored.
843 * @param interfacesDict Map containing D-Bus interfaces and their properties
844 * for the specified inventory item.
845 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000846inline void storeInventoryItemData(
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500847 InventoryItem& inventoryItem,
Michael Shen80f79a42023-08-24 13:41:53 +0000848 const dbus::utility::DBusInterfacesMap& interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500849{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500850 // Get properties from Inventory.Item interface
Ed Tanous711ac7a2021-12-20 09:34:41 -0800851
Ed Tanous9eb808c2022-01-25 10:19:23 -0800852 for (const auto& [interface, values] : interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500853 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800854 if (interface == "xyz.openbmc_project.Inventory.Item")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500855 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800856 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500857 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800858 if (name == "Present")
859 {
860 const bool* value = std::get_if<bool>(&dbusValue);
861 if (value != nullptr)
862 {
863 inventoryItem.isPresent = *value;
864 }
865 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500866 }
867 }
Ed Tanous711ac7a2021-12-20 09:34:41 -0800868 // Check if Inventory.Item.PowerSupply interface is present
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500869
Ed Tanous711ac7a2021-12-20 09:34:41 -0800870 if (interface == "xyz.openbmc_project.Inventory.Item.PowerSupply")
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500871 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800872 inventoryItem.isPowerSupply = true;
873 }
874
875 // Get properties from Inventory.Decorator.Asset interface
876 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
877 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800878 for (const auto& [name, dbusValue] : values)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500879 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800880 if (name == "Manufacturer")
881 {
882 const std::string* value =
883 std::get_if<std::string>(&dbusValue);
884 if (value != nullptr)
885 {
886 inventoryItem.manufacturer = *value;
887 }
888 }
889 if (name == "Model")
890 {
891 const std::string* value =
892 std::get_if<std::string>(&dbusValue);
893 if (value != nullptr)
894 {
895 inventoryItem.model = *value;
896 }
897 }
898 if (name == "SerialNumber")
899 {
900 const std::string* value =
901 std::get_if<std::string>(&dbusValue);
902 if (value != nullptr)
903 {
904 inventoryItem.serialNumber = *value;
905 }
906 }
907 if (name == "PartNumber")
908 {
909 const std::string* value =
910 std::get_if<std::string>(&dbusValue);
911 if (value != nullptr)
912 {
913 inventoryItem.partNumber = *value;
914 }
915 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500916 }
917 }
918
Ed Tanous711ac7a2021-12-20 09:34:41 -0800919 if (interface ==
920 "xyz.openbmc_project.State.Decorator.OperationalStatus")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500921 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800922 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500923 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800924 if (name == "Functional")
925 {
926 const bool* value = std::get_if<bool>(&dbusValue);
927 if (value != nullptr)
928 {
929 inventoryItem.isFunctional = *value;
930 }
931 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500932 }
933 }
934 }
935}
936
937/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500938 * @brief Gets D-Bus data for inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500939 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500940 * Uses the specified connections (services) to obtain D-Bus data for inventory
941 * items associated with sensors. Stores the resulting data in the
942 * inventoryItems vector.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500943 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500944 * This data is later used to provide sensor property values in the JSON
945 * response.
946 *
947 * Finds the inventory item data asynchronously. Invokes callback when data has
948 * been obtained.
949 *
950 * The callback must have the following signature:
951 * @code
Anthony Wilsond5005492019-07-31 16:34:17 -0500952 * callback(void)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500953 * @endcode
954 *
955 * This function is called recursively, obtaining data asynchronously from one
956 * connection in each call. This ensures the callback is not invoked until the
957 * last asynchronous function has completed.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500958 *
959 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500960 * @param inventoryItems D-Bus inventory items associated with sensors.
961 * @param invConnections Connections that provide data for the inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500962 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500963 * @param callback Callback to invoke when inventory data has been obtained.
964 * @param invConnectionsIndex Current index in invConnections. Only specified
965 * in recursive calls to this function.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500966 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500967template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -0700968void getInventoryItemsData(
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500969 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500970 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Ed Tanousd0090732022-10-04 17:22:56 -0700971 std::shared_ptr<std::set<std::string>> invConnections, Callback&& callback,
972 size_t invConnectionsIndex = 0)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500973{
Ed Tanous62598e32023-07-17 17:06:25 -0700974 BMCWEB_LOG_DEBUG("getInventoryItemsData enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500975
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500976 // If no more connections left, call callback
977 if (invConnectionsIndex >= invConnections->size())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500978 {
Anthony Wilsond5005492019-07-31 16:34:17 -0500979 callback();
Ed Tanous62598e32023-07-17 17:06:25 -0700980 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500981 return;
982 }
983
984 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +0000985 auto it = invConnections->begin();
986 std::advance(it, invConnectionsIndex);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500987 if (it != invConnections->end())
988 {
989 const std::string& invConnection = *it;
990
George Liu5eb468d2023-06-20 17:03:24 +0800991 // Get all object paths and their interfaces for current connection
992 sdbusplus::message::object_path path("/xyz/openbmc_project/inventory");
993 dbus::utility::getManagedObjects(
994 invConnection, path,
995 [sensorsAsyncResp, inventoryItems, invConnections,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700996 callback = std::forward<Callback>(callback), invConnectionsIndex](
George Liu5eb468d2023-06-20 17:03:24 +0800997 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -0700998 const dbus::utility::ManagedObjectType& resp) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400999 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler enter");
1000 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001001 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001002 BMCWEB_LOG_ERROR(
1003 "getInventoryItemsData respHandler DBus error {}", ec);
1004 messages::internalError(sensorsAsyncResp->asyncResp->res);
1005 return;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001006 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001007
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001008 // Loop through returned object paths
1009 for (const auto& objDictEntry : resp)
1010 {
1011 const std::string& objPath =
1012 static_cast<const std::string&>(objDictEntry.first);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001013
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001014 // If this object path is one of the specified inventory
1015 // items
1016 InventoryItem* inventoryItem =
1017 findInventoryItem(inventoryItems, objPath);
1018 if (inventoryItem != nullptr)
1019 {
1020 // Store inventory data in InventoryItem
1021 storeInventoryItemData(*inventoryItem,
1022 objDictEntry.second);
1023 }
1024 }
1025
1026 // Recurse to get inventory item data from next connection
1027 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1028 invConnections, std::move(callback),
1029 invConnectionsIndex + 1);
1030
1031 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler exit");
1032 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001033 }
1034
Ed Tanous62598e32023-07-17 17:06:25 -07001035 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001036}
1037
1038/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001039 * @brief Gets connections that provide D-Bus data for inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001040 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001041 * Gets the D-Bus connections (services) that provide data for the inventory
1042 * items that are associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001043 *
1044 * Finds the connections asynchronously. Invokes callback when information has
1045 * been obtained.
1046 *
1047 * The callback must have the following signature:
1048 * @code
Nan Zhoufe04d492022-06-22 17:10:41 +00001049 * callback(std::shared_ptr<std::set<std::string>> invConnections)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001050 * @endcode
1051 *
1052 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001053 * @param inventoryItems D-Bus inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001054 * @param callback Callback to invoke when connections have been obtained.
1055 */
1056template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001057void getInventoryItemsConnections(
Ed Tanousb5a76932020-09-29 16:16:58 -07001058 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1059 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001060 Callback&& callback)
1061{
Ed Tanous62598e32023-07-17 17:06:25 -07001062 BMCWEB_LOG_DEBUG("getInventoryItemsConnections enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001063
1064 const std::string path = "/xyz/openbmc_project/inventory";
George Liue99073f2022-12-09 11:06:16 +08001065 constexpr std::array<std::string_view, 4> interfaces = {
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001066 "xyz.openbmc_project.Inventory.Item",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001067 "xyz.openbmc_project.Inventory.Item.PowerSupply",
1068 "xyz.openbmc_project.Inventory.Decorator.Asset",
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001069 "xyz.openbmc_project.State.Decorator.OperationalStatus"};
1070
George Liue99073f2022-12-09 11:06:16 +08001071 // Make call to ObjectMapper to find all inventory items
1072 dbus::utility::getSubTree(
1073 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001074 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001075 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001076 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001077 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001078 // Response handler for parsing output from GetSubTree
1079 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler enter");
1080 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001081 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001082 messages::internalError(sensorsAsyncResp->asyncResp->res);
1083 BMCWEB_LOG_ERROR(
1084 "getInventoryItemsConnections respHandler DBus error {}",
1085 ec);
1086 return;
1087 }
1088
1089 // Make unique list of connections for desired inventory items
1090 std::shared_ptr<std::set<std::string>> invConnections =
1091 std::make_shared<std::set<std::string>>();
1092
1093 // Loop through objects from GetSubTree
1094 for (const std::pair<std::string,
1095 std::vector<std::pair<
1096 std::string, std::vector<std::string>>>>&
1097 object : subtree)
1098 {
1099 // Check if object path is one of the specified inventory items
1100 const std::string& objPath = object.first;
1101 if (findInventoryItem(inventoryItems, objPath) != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001102 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001103 // Store all connections to inventory item
1104 for (const std::pair<std::string, std::vector<std::string>>&
1105 objData : object.second)
1106 {
1107 const std::string& invConnection = objData.first;
1108 invConnections->insert(invConnection);
1109 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001110 }
1111 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001112
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001113 callback(invConnections);
1114 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler exit");
1115 });
Ed Tanous62598e32023-07-17 17:06:25 -07001116 BMCWEB_LOG_DEBUG("getInventoryItemsConnections exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001117}
1118
1119/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001120 * @brief Gets associations from sensors to inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001121 *
1122 * Looks for ObjectMapper associations from the specified sensors to related
Anthony Wilsond5005492019-07-31 16:34:17 -05001123 * inventory items. Then finds the associations from those inventory items to
1124 * their LEDs, if any.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001125 *
1126 * Finds the inventory items asynchronously. Invokes callback when information
1127 * has been obtained.
1128 *
1129 * The callback must have the following signature:
1130 * @code
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001131 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001132 * @endcode
1133 *
1134 * @param sensorsAsyncResp Pointer to object holding response data.
1135 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001136 * implements ObjectManager.
1137 * @param callback Callback to invoke when inventory items have been obtained.
1138 */
1139template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001140void getInventoryItemAssociations(
Ed Tanousb5a76932020-09-29 16:16:58 -07001141 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001142 const std::shared_ptr<std::set<std::string>>& sensorNames,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001143 Callback&& callback)
1144{
Ed Tanous62598e32023-07-17 17:06:25 -07001145 BMCWEB_LOG_DEBUG("getInventoryItemAssociations enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001146
George Liu5eb468d2023-06-20 17:03:24 +08001147 // Call GetManagedObjects on the ObjectMapper to get all associations
1148 sdbusplus::message::object_path path("/");
1149 dbus::utility::getManagedObjects(
1150 "xyz.openbmc_project.ObjectMapper", path,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001151 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001152 sensorNames](const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001153 const dbus::utility::ManagedObjectType& resp) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001154 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler enter");
1155 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001156 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001157 BMCWEB_LOG_ERROR(
1158 "getInventoryItemAssociations respHandler DBus error {}",
1159 ec);
1160 messages::internalError(sensorsAsyncResp->asyncResp->res);
1161 return;
1162 }
1163
1164 // Create vector to hold list of inventory items
1165 std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1166 std::make_shared<std::vector<InventoryItem>>();
1167
1168 // Loop through returned object paths
1169 std::string sensorAssocPath;
1170 sensorAssocPath.reserve(128); // avoid memory allocations
1171 for (const auto& objDictEntry : resp)
1172 {
1173 const std::string& objPath =
1174 static_cast<const std::string&>(objDictEntry.first);
1175
1176 // If path is inventory association for one of the specified
1177 // sensors
1178 for (const std::string& sensorName : *sensorNames)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001179 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001180 sensorAssocPath = sensorName;
1181 sensorAssocPath += "/inventory";
1182 if (objPath == sensorAssocPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001183 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001184 // Get Association interface for object path
1185 for (const auto& [interface, values] :
1186 objDictEntry.second)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001187 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001188 if (interface == "xyz.openbmc_project.Association")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001189 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001190 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001191 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001192 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001193 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001194 const std::vector<std::string>*
1195 endpoints = std::get_if<
1196 std::vector<std::string>>(
1197 &value);
1198 if ((endpoints != nullptr) &&
1199 !endpoints->empty())
1200 {
1201 // Add inventory item to vector
1202 const std::string& invItemPath =
1203 endpoints->front();
1204 addInventoryItem(inventoryItems,
1205 invItemPath,
1206 sensorName);
1207 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001208 }
1209 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001210 }
1211 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001212 break;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001213 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001214 }
1215 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001216
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001217 // Now loop through the returned object paths again, this time to
1218 // find the leds associated with the inventory items we just found
1219 std::string inventoryAssocPath;
1220 inventoryAssocPath.reserve(128); // avoid memory allocations
1221 for (const auto& objDictEntry : resp)
Anthony Wilsond5005492019-07-31 16:34:17 -05001222 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001223 const std::string& objPath =
1224 static_cast<const std::string&>(objDictEntry.first);
1225
1226 for (InventoryItem& inventoryItem : *inventoryItems)
Anthony Wilsond5005492019-07-31 16:34:17 -05001227 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001228 inventoryAssocPath = inventoryItem.objectPath;
1229 inventoryAssocPath += "/leds";
1230 if (objPath == inventoryAssocPath)
Anthony Wilsond5005492019-07-31 16:34:17 -05001231 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001232 for (const auto& [interface, values] :
1233 objDictEntry.second)
Anthony Wilsond5005492019-07-31 16:34:17 -05001234 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001235 if (interface == "xyz.openbmc_project.Association")
Anthony Wilsond5005492019-07-31 16:34:17 -05001236 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001237 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001238 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001239 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001240 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001241 const std::vector<std::string>*
1242 endpoints = std::get_if<
1243 std::vector<std::string>>(
1244 &value);
1245 if ((endpoints != nullptr) &&
1246 !endpoints->empty())
1247 {
1248 // Add inventory item to vector
1249 // Store LED path in inventory item
1250 const std::string& ledPath =
1251 endpoints->front();
1252 inventoryItem.ledObjectPath =
1253 ledPath;
1254 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001255 }
1256 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001257 }
1258 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001259
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001260 break;
1261 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001262 }
1263 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001264 callback(inventoryItems);
1265 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler exit");
1266 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001267
Ed Tanous62598e32023-07-17 17:06:25 -07001268 BMCWEB_LOG_DEBUG("getInventoryItemAssociations exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001269}
1270
1271/**
Anthony Wilsond5005492019-07-31 16:34:17 -05001272 * @brief Gets D-Bus data for inventory item leds associated with sensors.
1273 *
1274 * Uses the specified connections (services) to obtain D-Bus data for inventory
1275 * item leds associated with sensors. Stores the resulting data in the
1276 * inventoryItems vector.
1277 *
1278 * This data is later used to provide sensor property values in the JSON
1279 * response.
1280 *
1281 * Finds the inventory item led data asynchronously. Invokes callback when data
1282 * has been obtained.
1283 *
1284 * The callback must have the following signature:
1285 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001286 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001287 * @endcode
1288 *
1289 * This function is called recursively, obtaining data asynchronously from one
1290 * connection in each call. This ensures the callback is not invoked until the
1291 * last asynchronous function has completed.
1292 *
1293 * @param sensorsAsyncResp Pointer to object holding response data.
1294 * @param inventoryItems D-Bus inventory items associated with sensors.
1295 * @param ledConnections Connections that provide data for the inventory leds.
1296 * @param callback Callback to invoke when inventory data has been obtained.
1297 * @param ledConnectionsIndex Current index in ledConnections. Only specified
1298 * in recursive calls to this function.
1299 */
1300template <typename Callback>
1301void getInventoryLedData(
1302 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1303 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001304 std::shared_ptr<std::map<std::string, std::string>> ledConnections,
Anthony Wilsond5005492019-07-31 16:34:17 -05001305 Callback&& callback, size_t ledConnectionsIndex = 0)
1306{
Ed Tanous62598e32023-07-17 17:06:25 -07001307 BMCWEB_LOG_DEBUG("getInventoryLedData enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001308
1309 // If no more connections left, call callback
1310 if (ledConnectionsIndex >= ledConnections->size())
1311 {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001312 callback();
Ed Tanous62598e32023-07-17 17:06:25 -07001313 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001314 return;
1315 }
1316
1317 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +00001318 auto it = ledConnections->begin();
1319 std::advance(it, ledConnectionsIndex);
Anthony Wilsond5005492019-07-31 16:34:17 -05001320 if (it != ledConnections->end())
1321 {
1322 const std::string& ledPath = (*it).first;
1323 const std::string& ledConnection = (*it).second;
1324 // Response handler for Get State property
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001325 auto respHandler =
1326 [sensorsAsyncResp, inventoryItems, ledConnections, ledPath,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001327 callback = std::forward<Callback>(callback),
1328 ledConnectionsIndex](const boost::system::error_code& ec,
1329 const std::string& state) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001330 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler enter");
1331 if (ec)
1332 {
1333 BMCWEB_LOG_ERROR(
1334 "getInventoryLedData respHandler DBus error {}", ec);
1335 messages::internalError(sensorsAsyncResp->asyncResp->res);
1336 return;
1337 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001338
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001339 BMCWEB_LOG_DEBUG("Led state: {}", state);
1340 // Find inventory item with this LED object path
1341 InventoryItem* inventoryItem =
1342 findInventoryItemForLed(*inventoryItems, ledPath);
1343 if (inventoryItem != nullptr)
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001344 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001345 // Store LED state in InventoryItem
1346 if (state.ends_with("On"))
1347 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001348 inventoryItem->ledState = sensor_utils::LedState::ON;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001349 }
1350 else if (state.ends_with("Blink"))
1351 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001352 inventoryItem->ledState = sensor_utils::LedState::BLINK;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001353 }
1354 else if (state.ends_with("Off"))
1355 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001356 inventoryItem->ledState = sensor_utils::LedState::OFF;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001357 }
1358 else
1359 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001360 inventoryItem->ledState =
1361 sensor_utils::LedState::UNKNOWN;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001362 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001363 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001364
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001365 // Recurse to get LED data from next connection
1366 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1367 ledConnections, std::move(callback),
1368 ledConnectionsIndex + 1);
Anthony Wilsond5005492019-07-31 16:34:17 -05001369
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001370 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler exit");
1371 };
Anthony Wilsond5005492019-07-31 16:34:17 -05001372
1373 // Get the State property for the current LED
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001374 sdbusplus::asio::getProperty<std::string>(
1375 *crow::connections::systemBus, ledConnection, ledPath,
1376 "xyz.openbmc_project.Led.Physical", "State",
1377 std::move(respHandler));
Anthony Wilsond5005492019-07-31 16:34:17 -05001378 }
1379
Ed Tanous62598e32023-07-17 17:06:25 -07001380 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001381}
1382
1383/**
1384 * @brief Gets LED data for LEDs associated with given inventory items.
1385 *
1386 * Gets the D-Bus connections (services) that provide LED data for the LEDs
1387 * associated with the specified inventory items. Then gets the LED data from
1388 * each connection and stores it in the inventory item.
1389 *
1390 * This data is later used to provide sensor property values in the JSON
1391 * response.
1392 *
1393 * Finds the LED data asynchronously. Invokes callback when information has
1394 * been obtained.
1395 *
1396 * The callback must have the following signature:
1397 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001398 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001399 * @endcode
1400 *
1401 * @param sensorsAsyncResp Pointer to object holding response data.
1402 * @param inventoryItems D-Bus inventory items associated with sensors.
1403 * @param callback Callback to invoke when inventory items have been obtained.
1404 */
1405template <typename Callback>
1406void getInventoryLeds(
1407 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1408 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1409 Callback&& callback)
1410{
Ed Tanous62598e32023-07-17 17:06:25 -07001411 BMCWEB_LOG_DEBUG("getInventoryLeds enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001412
1413 const std::string path = "/xyz/openbmc_project";
George Liue99073f2022-12-09 11:06:16 +08001414 constexpr std::array<std::string_view, 1> interfaces = {
Anthony Wilsond5005492019-07-31 16:34:17 -05001415 "xyz.openbmc_project.Led.Physical"};
1416
George Liue99073f2022-12-09 11:06:16 +08001417 // Make call to ObjectMapper to find all inventory items
1418 dbus::utility::getSubTree(
1419 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001420 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001421 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001422 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001423 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001424 // Response handler for parsing output from GetSubTree
1425 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler enter");
1426 if (ec)
Anthony Wilsond5005492019-07-31 16:34:17 -05001427 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001428 messages::internalError(sensorsAsyncResp->asyncResp->res);
1429 BMCWEB_LOG_ERROR("getInventoryLeds respHandler DBus error {}",
1430 ec);
1431 return;
Anthony Wilsond5005492019-07-31 16:34:17 -05001432 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001433
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001434 // Build map of LED object paths to connections
1435 std::shared_ptr<std::map<std::string, std::string>> ledConnections =
1436 std::make_shared<std::map<std::string, std::string>>();
1437
1438 // Loop through objects from GetSubTree
1439 for (const std::pair<std::string,
1440 std::vector<std::pair<
1441 std::string, std::vector<std::string>>>>&
1442 object : subtree)
1443 {
1444 // Check if object path is LED for one of the specified
1445 // inventory items
1446 const std::string& ledPath = object.first;
1447 if (findInventoryItemForLed(*inventoryItems, ledPath) !=
1448 nullptr)
1449 {
1450 // Add mapping from ledPath to connection
1451 const std::string& connection =
1452 object.second.begin()->first;
1453 (*ledConnections)[ledPath] = connection;
1454 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", ledPath,
1455 connection);
1456 }
1457 }
1458
1459 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1460 ledConnections, std::move(callback));
1461 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler exit");
1462 });
Ed Tanous62598e32023-07-17 17:06:25 -07001463 BMCWEB_LOG_DEBUG("getInventoryLeds exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001464}
1465
1466/**
Gunnar Mills42cbe532019-08-15 15:26:54 -05001467 * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent
1468 *
1469 * Uses the specified connections (services) (currently assumes just one) to
1470 * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in
1471 * the inventoryItems vector. Only stores data in Power Supply inventoryItems.
1472 *
1473 * This data is later used to provide sensor property values in the JSON
1474 * response.
1475 *
1476 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1477 * when data has been obtained.
1478 *
1479 * The callback must have the following signature:
1480 * @code
1481 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1482 * @endcode
1483 *
1484 * @param sensorsAsyncResp Pointer to object holding response data.
1485 * @param inventoryItems D-Bus inventory items associated with sensors.
1486 * @param psAttributesConnections Connections that provide data for the Power
1487 * Supply Attributes
1488 * @param callback Callback to invoke when data has been obtained.
1489 */
1490template <typename Callback>
1491void getPowerSupplyAttributesData(
Ed Tanousb5a76932020-09-29 16:16:58 -07001492 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001493 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001494 const std::map<std::string, std::string>& psAttributesConnections,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001495 Callback&& callback)
1496{
Ed Tanous62598e32023-07-17 17:06:25 -07001497 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001498
1499 if (psAttributesConnections.empty())
1500 {
Ed Tanous62598e32023-07-17 17:06:25 -07001501 BMCWEB_LOG_DEBUG("Can't find PowerSupplyAttributes, no connections!");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001502 callback(inventoryItems);
1503 return;
1504 }
1505
1506 // Assuming just one connection (service) for now
Nan Zhoufe04d492022-06-22 17:10:41 +00001507 auto it = psAttributesConnections.begin();
Gunnar Mills42cbe532019-08-15 15:26:54 -05001508
1509 const std::string& psAttributesPath = (*it).first;
1510 const std::string& psAttributesConnection = (*it).second;
1511
1512 // Response handler for Get DeratingFactor property
Patrick Williams5a39f772023-10-20 11:20:21 -05001513 auto respHandler = [sensorsAsyncResp, inventoryItems,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001514 callback = std::forward<Callback>(callback)](
Patrick Williams5a39f772023-10-20 11:20:21 -05001515 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001516 uint32_t value) mutable {
Ed Tanous62598e32023-07-17 17:06:25 -07001517 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001518 if (ec)
1519 {
Ed Tanous62598e32023-07-17 17:06:25 -07001520 BMCWEB_LOG_ERROR(
1521 "getPowerSupplyAttributesData respHandler DBus error {}", ec);
zhanghch058d1b46d2021-04-01 11:18:24 +08001522 messages::internalError(sensorsAsyncResp->asyncResp->res);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001523 return;
1524 }
1525
Ed Tanous62598e32023-07-17 17:06:25 -07001526 BMCWEB_LOG_DEBUG("PS EfficiencyPercent value: {}", value);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001527 // Store value in Power Supply Inventory Items
1528 for (InventoryItem& inventoryItem : *inventoryItems)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001529 {
Ed Tanous55f79e62022-01-25 11:26:16 -08001530 if (inventoryItem.isPowerSupply)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001531 {
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001532 inventoryItem.powerSupplyEfficiencyPercent =
1533 static_cast<int>(value);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001534 }
1535 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001536
Ed Tanous62598e32023-07-17 17:06:25 -07001537 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001538 callback(inventoryItems);
1539 };
1540
1541 // Get the DeratingFactor property for the PowerSupplyAttributes
1542 // Currently only property on the interface/only one we care about
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001543 sdbusplus::asio::getProperty<uint32_t>(
1544 *crow::connections::systemBus, psAttributesConnection, psAttributesPath,
1545 "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
1546 std::move(respHandler));
Gunnar Mills42cbe532019-08-15 15:26:54 -05001547
Ed Tanous62598e32023-07-17 17:06:25 -07001548 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001549}
1550
1551/**
1552 * @brief Gets the Power Supply Attributes such as EfficiencyPercent
1553 *
1554 * Gets the D-Bus connection (service) that provides Power Supply Attributes
1555 * data. Then gets the Power Supply Attributes data from the connection
1556 * (currently just assumes 1 connection) and stores the data in the inventory
1557 * item.
1558 *
1559 * This data is later used to provide sensor property values in the JSON
1560 * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish.
1561 *
1562 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1563 * when information has been obtained.
1564 *
1565 * The callback must have the following signature:
1566 * @code
1567 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1568 * @endcode
1569 *
1570 * @param sensorsAsyncResp Pointer to object holding response data.
1571 * @param inventoryItems D-Bus inventory items associated with sensors.
1572 * @param callback Callback to invoke when data has been obtained.
1573 */
1574template <typename Callback>
1575void getPowerSupplyAttributes(
1576 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1577 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1578 Callback&& callback)
1579{
Ed Tanous62598e32023-07-17 17:06:25 -07001580 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001581
1582 // Only need the power supply attributes when the Power Schema
Janet Adkins0c728b42024-08-29 11:09:10 -05001583 if (sensorsAsyncResp->chassisSubNode != sensors::powerNodeStr)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001584 {
Ed Tanous62598e32023-07-17 17:06:25 -07001585 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit since not Power");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001586 callback(inventoryItems);
1587 return;
1588 }
1589
George Liue99073f2022-12-09 11:06:16 +08001590 constexpr std::array<std::string_view, 1> interfaces = {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001591 "xyz.openbmc_project.Control.PowerSupplyAttributes"};
1592
George Liue99073f2022-12-09 11:06:16 +08001593 // Make call to ObjectMapper to find the PowerSupplyAttributes service
1594 dbus::utility::getSubTree(
1595 "/xyz/openbmc_project", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001596 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001597 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001598 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001599 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001600 // Response handler for parsing output from GetSubTree
1601 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler enter");
1602 if (ec)
1603 {
1604 messages::internalError(sensorsAsyncResp->asyncResp->res);
1605 BMCWEB_LOG_ERROR(
1606 "getPowerSupplyAttributes respHandler DBus error {}", ec);
1607 return;
1608 }
1609 if (subtree.empty())
1610 {
1611 BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
1612 callback(inventoryItems);
1613 return;
1614 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001615
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001616 // Currently we only support 1 power supply attribute, use this for
1617 // all the power supplies. Build map of object path to connection.
1618 // Assume just 1 connection and 1 path for now.
1619 std::map<std::string, std::string> psAttributesConnections;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001620
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001621 if (subtree[0].first.empty() || subtree[0].second.empty())
1622 {
1623 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1624 callback(inventoryItems);
1625 return;
1626 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001627
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001628 const std::string& psAttributesPath = subtree[0].first;
1629 const std::string& connection = subtree[0].second.begin()->first;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001630
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001631 if (connection.empty())
1632 {
1633 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1634 callback(inventoryItems);
1635 return;
1636 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001637
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001638 psAttributesConnections[psAttributesPath] = connection;
1639 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", psAttributesPath,
1640 connection);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001641
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001642 getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems,
1643 psAttributesConnections,
1644 std::move(callback));
1645 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler exit");
1646 });
Ed Tanous62598e32023-07-17 17:06:25 -07001647 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001648}
1649
1650/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001651 * @brief Gets inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001652 *
1653 * Finds the inventory items that are associated with the specified sensors.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001654 * Then gets D-Bus data for the inventory items, such as presence and VPD.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001655 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001656 * This data is later used to provide sensor property values in the JSON
1657 * response.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001658 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001659 * Finds the inventory items asynchronously. Invokes callback when the
1660 * inventory items have been obtained.
1661 *
1662 * The callback must have the following signature:
1663 * @code
1664 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1665 * @endcode
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001666 *
1667 * @param sensorsAsyncResp Pointer to object holding response data.
1668 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001669 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001670 * @param callback Callback to invoke when inventory items have been obtained.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001671 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001672template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001673inline void
Ed Tanousd0090732022-10-04 17:22:56 -07001674 getInventoryItems(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1675 const std::shared_ptr<std::set<std::string>> sensorNames,
1676 Callback&& callback)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001677{
Ed Tanous62598e32023-07-17 17:06:25 -07001678 BMCWEB_LOG_DEBUG("getInventoryItems enter");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001679 auto getInventoryItemAssociationsCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -07001680 [sensorsAsyncResp, callback = std::forward<Callback>(callback)](
Ed Tanous4e0d8782024-09-06 15:16:41 -07001681 std::shared_ptr<std::vector<InventoryItem>>
1682 inventoryItems) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001683 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb enter");
1684 auto getInventoryItemsConnectionsCb =
1685 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001686 callback = std::forward<Callback>(callback)](
1687 std::shared_ptr<std::set<std::string>>
1688 invConnections) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001689 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb enter");
1690 auto getInventoryItemsDataCb =
1691 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001692 callback =
1693 std::forward<Callback>(callback)]() mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001694 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001695
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001696 auto getInventoryLedsCb =
1697 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001698 callback = std::forward<Callback>(
1699 callback)]() mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001700 BMCWEB_LOG_DEBUG(
1701 "getInventoryLedsCb enter");
1702 // Find Power Supply Attributes and get the
1703 // data
1704 getPowerSupplyAttributes(
1705 sensorsAsyncResp, inventoryItems,
1706 std::move(callback));
1707 BMCWEB_LOG_DEBUG("getInventoryLedsCb exit");
1708 };
1709
1710 // Find led connections and get the data
1711 getInventoryLeds(sensorsAsyncResp, inventoryItems,
1712 std::move(getInventoryLedsCb));
1713 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb exit");
1714 };
1715
1716 // Get inventory item data from connections
1717 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1718 invConnections,
1719 std::move(getInventoryItemsDataCb));
1720 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001721 };
1722
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001723 // Get connections that provide inventory item data
1724 getInventoryItemsConnections(
1725 sensorsAsyncResp, inventoryItems,
1726 std::move(getInventoryItemsConnectionsCb));
1727 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001728 };
1729
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001730 // Get associations from sensors to inventory items
Ed Tanousd0090732022-10-04 17:22:56 -07001731 getInventoryItemAssociations(sensorsAsyncResp, sensorNames,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001732 std::move(getInventoryItemAssociationsCb));
Ed Tanous62598e32023-07-17 17:06:25 -07001733 BMCWEB_LOG_DEBUG("getInventoryItems exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001734}
1735
1736/**
1737 * @brief Returns JSON PowerSupply object for the specified inventory item.
1738 *
1739 * Searches for a JSON PowerSupply object that matches the specified inventory
1740 * item. If one is not found, a new PowerSupply object is added to the JSON
1741 * array.
1742 *
1743 * Multiple sensors are often associated with one power supply inventory item.
1744 * As a result, multiple sensor values are stored in one JSON PowerSupply
1745 * object.
1746 *
1747 * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1748 * @param inventoryItem Inventory item for the power supply.
1749 * @param chassisId Chassis that contains the power supply.
1750 * @return JSON PowerSupply object for the specified inventory item.
1751 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001752inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001753 const InventoryItem& inventoryItem,
1754 const std::string& chassisId)
1755{
Ed Tanous18f8f602023-07-18 10:07:23 -07001756 std::string nameS;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001757 nameS.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001758 std::ranges::replace_copy(inventoryItem.name, nameS.begin(), '_', ' ');
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001759 // Check if matching PowerSupply object already exists in JSON array
1760 for (nlohmann::json& powerSupply : powerSupplyArray)
1761 {
Ed Tanous18f8f602023-07-18 10:07:23 -07001762 nlohmann::json::iterator nameIt = powerSupply.find("Name");
1763 if (nameIt == powerSupply.end())
1764 {
1765 continue;
1766 }
1767 const std::string* name = nameIt->get_ptr<std::string*>();
1768 if (name == nullptr)
1769 {
1770 continue;
1771 }
1772 if (nameS == *name)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001773 {
1774 return powerSupply;
1775 }
1776 }
1777
1778 // Add new PowerSupply object to JSON array
1779 powerSupplyArray.push_back({});
1780 nlohmann::json& powerSupply = powerSupplyArray.back();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001781 boost::urls::url url =
1782 boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
Willy Tueddfc432022-09-26 16:46:38 +00001783 url.set_fragment(("/PowerSupplies"_json_pointer).to_string());
1784 powerSupply["@odata.id"] = std::move(url);
Ed Tanous18f8f602023-07-18 10:07:23 -07001785 std::string escaped;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001786 escaped.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001787 std::ranges::replace_copy(inventoryItem.name, escaped.begin(), '_', ' ');
1788 powerSupply["Name"] = std::move(escaped);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001789 powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1790 powerSupply["Model"] = inventoryItem.model;
1791 powerSupply["PartNumber"] = inventoryItem.partNumber;
1792 powerSupply["SerialNumber"] = inventoryItem.serialNumber;
Janet Adkinsc9563602024-08-28 11:37:46 -05001793 sensor_utils::setLedState(powerSupply, &inventoryItem);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001794
Gunnar Mills42cbe532019-08-15 15:26:54 -05001795 if (inventoryItem.powerSupplyEfficiencyPercent >= 0)
1796 {
1797 powerSupply["EfficiencyPercent"] =
1798 inventoryItem.powerSupplyEfficiencyPercent;
1799 }
1800
Janet Adkinsc9563602024-08-28 11:37:46 -05001801 powerSupply["Status"]["State"] =
1802 sensor_utils::getState(&inventoryItem, true);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001803 const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1804 powerSupply["Status"]["Health"] = health;
1805
1806 return powerSupply;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001807}
1808
1809/**
Shawn McCarneyde629b62019-03-08 10:42:51 -06001810 * @brief Gets the values of the specified sensors.
1811 *
1812 * Stores the results as JSON in the SensorsAsyncResp.
1813 *
1814 * Gets the sensor values asynchronously. Stores the results later when the
1815 * information has been obtained.
1816 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001817 * The sensorNames set contains all requested sensors for the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001818 *
1819 * To minimize the number of DBus calls, the DBus method
1820 * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1821 * values of all sensors provided by a connection (service).
1822 *
1823 * The connections set contains all the connections that provide sensor values.
1824 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001825 * The InventoryItem vector contains D-Bus inventory items associated with the
1826 * sensors. Inventory item data is needed for some Redfish sensor properties.
1827 *
Shawn McCarneyde629b62019-03-08 10:42:51 -06001828 * @param SensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001829 * @param sensorNames All requested sensors within the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001830 * @param connections Connections that provide sensor values.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001831 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001832 * @param inventoryItems Inventory items associated with the sensors.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001833 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001834inline void getSensorData(
Ed Tanous81ce6092020-12-17 16:54:55 +00001835 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001836 const std::shared_ptr<std::set<std::string>>& sensorNames,
1837 const std::set<std::string>& connections,
Ed Tanousb5a76932020-09-29 16:16:58 -07001838 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001839{
Ed Tanous62598e32023-07-17 17:06:25 -07001840 BMCWEB_LOG_DEBUG("getSensorData enter");
Shawn McCarneyde629b62019-03-08 10:42:51 -06001841 // Get managed objects from all services exposing sensors
1842 for (const std::string& connection : connections)
1843 {
George Liu5eb468d2023-06-20 17:03:24 +08001844 sdbusplus::message::object_path sensorPath(
1845 "/xyz/openbmc_project/sensors");
1846 dbus::utility::getManagedObjects(
1847 connection, sensorPath,
Ed Tanous002d39b2022-05-31 08:59:27 -07001848 [sensorsAsyncResp, sensorNames,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001849 inventoryItems](const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -07001850 const dbus::utility::ManagedObjectType& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001851 BMCWEB_LOG_DEBUG("getManagedObjectsCb enter");
1852 if (ec)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001853 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001854 BMCWEB_LOG_ERROR("getManagedObjectsCb DBUS error: {}", ec);
1855 messages::internalError(sensorsAsyncResp->asyncResp->res);
1856 return;
1857 }
Janet Adkins0c728b42024-08-29 11:09:10 -05001858 auto chassisSubNode = sensor_utils::chassisSubNodeFromString(
1859 sensorsAsyncResp->chassisSubNode);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001860 // Go through all objects and update response with sensor data
1861 for (const auto& objDictEntry : resp)
1862 {
1863 const std::string& objPath =
1864 static_cast<const std::string&>(objDictEntry.first);
1865 BMCWEB_LOG_DEBUG("getManagedObjectsCb parsing object {}",
Ed Tanous62598e32023-07-17 17:06:25 -07001866 objPath);
Shawn McCarneyde629b62019-03-08 10:42:51 -06001867
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001868 std::vector<std::string> split;
1869 // Reserve space for
1870 // /xyz/openbmc_project/sensors/<name>/<subname>
1871 split.reserve(6);
1872 // NOLINTNEXTLINE
1873 bmcweb::split(split, objPath, '/');
1874 if (split.size() < 6)
Nan Zhou928fefb2022-03-28 08:45:00 -07001875 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001876 BMCWEB_LOG_ERROR("Got path that isn't long enough {}",
1877 objPath);
1878 continue;
Nan Zhou928fefb2022-03-28 08:45:00 -07001879 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001880 // These indexes aren't intuitive, as split puts an empty
1881 // string at the beginning
1882 const std::string& sensorType = split[4];
1883 const std::string& sensorName = split[5];
1884 BMCWEB_LOG_DEBUG("sensorName {} sensorType {}", sensorName,
1885 sensorType);
1886 if (sensorNames->find(objPath) == sensorNames->end())
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001887 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001888 BMCWEB_LOG_DEBUG("{} not in sensor list ", sensorName);
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001889 continue;
1890 }
1891
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001892 // Find inventory item (if any) associated with sensor
1893 InventoryItem* inventoryItem =
1894 findInventoryItemForSensor(inventoryItems, objPath);
1895
1896 const std::string& sensorSchema =
1897 sensorsAsyncResp->chassisSubNode;
1898
1899 nlohmann::json* sensorJson = nullptr;
1900
Janet Adkins0c728b42024-08-29 11:09:10 -05001901 if (sensorSchema == sensors::sensorsNodeStr &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001902 !sensorsAsyncResp->efficientExpand)
Nan Zhou928fefb2022-03-28 08:45:00 -07001903 {
Janet Adkins1516c212024-08-14 13:22:41 -05001904 std::string sensorId =
1905 redfish::sensor_utils::getSensorId(sensorName,
1906 sensorType);
Ed Tanous677bb752022-09-15 10:52:19 -07001907
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001908 sensorsAsyncResp->asyncResp->res
1909 .jsonValue["@odata.id"] = boost::urls::format(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001910 "/redfish/v1/Chassis/{}/{}/{}",
Ed Tanous677bb752022-09-15 10:52:19 -07001911 sensorsAsyncResp->chassisId,
1912 sensorsAsyncResp->chassisSubNode, sensorId);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001913 sensorJson =
1914 &(sensorsAsyncResp->asyncResp->res.jsonValue);
Nan Zhou928fefb2022-03-28 08:45:00 -07001915 }
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001916 else
1917 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001918 std::string fieldName;
1919 if (sensorsAsyncResp->efficientExpand)
1920 {
1921 fieldName = "Members";
1922 }
1923 else if (sensorType == "temperature")
1924 {
1925 fieldName = "Temperatures";
1926 }
1927 else if (sensorType == "fan" ||
1928 sensorType == "fan_tach" ||
1929 sensorType == "fan_pwm")
1930 {
1931 fieldName = "Fans";
1932 }
1933 else if (sensorType == "voltage")
1934 {
1935 fieldName = "Voltages";
1936 }
1937 else if (sensorType == "power")
1938 {
1939 if (sensorName == "total_power")
1940 {
1941 fieldName = "PowerControl";
1942 }
1943 else if ((inventoryItem != nullptr) &&
1944 (inventoryItem->isPowerSupply))
1945 {
1946 fieldName = "PowerSupplies";
1947 }
1948 else
1949 {
1950 // Other power sensors are in SensorCollection
1951 continue;
1952 }
1953 }
1954 else
1955 {
1956 BMCWEB_LOG_ERROR(
1957 "Unsure how to handle sensorType {}",
1958 sensorType);
1959 continue;
1960 }
1961
1962 nlohmann::json& tempArray =
1963 sensorsAsyncResp->asyncResp->res
1964 .jsonValue[fieldName];
1965 if (fieldName == "PowerControl")
1966 {
1967 if (tempArray.empty())
1968 {
1969 // Put multiple "sensors" into a single
1970 // PowerControl. Follows MemberId naming and
1971 // naming in power.hpp.
1972 nlohmann::json::object_t power;
1973 boost::urls::url url = boost::urls::format(
1974 "/redfish/v1/Chassis/{}/{}",
1975 sensorsAsyncResp->chassisId,
1976 sensorsAsyncResp->chassisSubNode);
1977 url.set_fragment(
1978 (""_json_pointer / fieldName / "0")
1979 .to_string());
1980 power["@odata.id"] = std::move(url);
1981 tempArray.emplace_back(std::move(power));
1982 }
1983 sensorJson = &(tempArray.back());
1984 }
1985 else if (fieldName == "PowerSupplies")
1986 {
1987 if (inventoryItem != nullptr)
1988 {
1989 sensorJson = &(getPowerSupply(
1990 tempArray, *inventoryItem,
1991 sensorsAsyncResp->chassisId));
1992 }
1993 }
1994 else if (fieldName == "Members")
1995 {
Janet Adkins1516c212024-08-14 13:22:41 -05001996 std::string sensorId =
1997 redfish::sensor_utils::getSensorId(sensorName,
1998 sensorType);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001999
2000 nlohmann::json::object_t member;
2001 member["@odata.id"] = boost::urls::format(
2002 "/redfish/v1/Chassis/{}/{}/{}",
2003 sensorsAsyncResp->chassisId,
2004 sensorsAsyncResp->chassisSubNode, sensorId);
2005 tempArray.emplace_back(std::move(member));
2006 sensorJson = &(tempArray.back());
2007 }
2008 else
2009 {
2010 nlohmann::json::object_t member;
2011 boost::urls::url url = boost::urls::format(
2012 "/redfish/v1/Chassis/{}/{}",
2013 sensorsAsyncResp->chassisId,
2014 sensorsAsyncResp->chassisSubNode);
2015 url.set_fragment(
2016 (""_json_pointer / fieldName).to_string());
2017 member["@odata.id"] = std::move(url);
2018 tempArray.emplace_back(std::move(member));
2019 sensorJson = &(tempArray.back());
2020 }
2021 }
2022
2023 if (sensorJson != nullptr)
2024 {
Janet Adkins0c728b42024-08-29 11:09:10 -05002025 objectInterfacesToJson(
2026 sensorName, sensorType, chassisSubNode,
2027 objDictEntry.second, *sensorJson, inventoryItem);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002028
2029 std::string path = "/xyz/openbmc_project/sensors/";
2030 path += sensorType;
2031 path += "/";
2032 path += sensorName;
2033 sensorsAsyncResp->addMetadata(*sensorJson, path);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002034 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002035 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002036 if (sensorsAsyncResp.use_count() == 1)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002037 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002038 sortJSONResponse(sensorsAsyncResp);
Janet Adkins0c728b42024-08-29 11:09:10 -05002039 if (chassisSubNode ==
2040 sensor_utils::ChassisSubNode::sensorsNode &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002041 sensorsAsyncResp->efficientExpand)
2042 {
2043 sensorsAsyncResp->asyncResp->res
2044 .jsonValue["Members@odata.count"] =
2045 sensorsAsyncResp->asyncResp->res
2046 .jsonValue["Members"]
2047 .size();
2048 }
Janet Adkins0c728b42024-08-29 11:09:10 -05002049 else if (chassisSubNode ==
2050 sensor_utils::ChassisSubNode::thermalNode)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002051 {
2052 populateFanRedundancy(sensorsAsyncResp);
2053 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002054 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002055 BMCWEB_LOG_DEBUG("getManagedObjectsCb exit");
2056 });
Ed Tanous23a21a12020-07-25 04:45:05 +00002057 }
Ed Tanous62598e32023-07-17 17:06:25 -07002058 BMCWEB_LOG_DEBUG("getSensorData exit");
Shawn McCarneyde629b62019-03-08 10:42:51 -06002059}
2060
Nan Zhoufe04d492022-06-22 17:10:41 +00002061inline void
2062 processSensorList(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
2063 const std::shared_ptr<std::set<std::string>>& sensorNames)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002064{
Nan Zhoufe04d492022-06-22 17:10:41 +00002065 auto getConnectionCb = [sensorsAsyncResp, sensorNames](
2066 const std::set<std::string>& connections) {
Ed Tanous62598e32023-07-17 17:06:25 -07002067 BMCWEB_LOG_DEBUG("getConnectionCb enter");
Ed Tanousd0090732022-10-04 17:22:56 -07002068 auto getInventoryItemsCb =
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002069 [sensorsAsyncResp, sensorNames, connections](
2070 const std::shared_ptr<std::vector<InventoryItem>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07002071 inventoryItems) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002072 BMCWEB_LOG_DEBUG("getInventoryItemsCb enter");
2073 // Get sensor data and store results in JSON
2074 getSensorData(sensorsAsyncResp, sensorNames, connections,
2075 inventoryItems);
2076 BMCWEB_LOG_DEBUG("getInventoryItemsCb exit");
2077 };
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002078
Ed Tanousd0090732022-10-04 17:22:56 -07002079 // Get inventory items associated with sensors
2080 getInventoryItems(sensorsAsyncResp, sensorNames,
2081 std::move(getInventoryItemsCb));
2082
Ed Tanous62598e32023-07-17 17:06:25 -07002083 BMCWEB_LOG_DEBUG("getConnectionCb exit");
Ed Tanous002d39b2022-05-31 08:59:27 -07002084 };
2085
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002086 // Get set of connections that provide sensor values
Ed Tanous81ce6092020-12-17 16:54:55 +00002087 getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002088}
2089
Shawn McCarneyde629b62019-03-08 10:42:51 -06002090/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002091 * @brief Entry point for retrieving sensors data related to requested
2092 * chassis.
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02002093 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002094 */
Ed Tanousb5a76932020-09-29 16:16:58 -07002095inline void
Ed Tanous81ce6092020-12-17 16:54:55 +00002096 getChassisData(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002097{
Ed Tanous62598e32023-07-17 17:06:25 -07002098 BMCWEB_LOG_DEBUG("getChassisData enter");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002099 auto getChassisCb =
Ed Tanous81ce6092020-12-17 16:54:55 +00002100 [sensorsAsyncResp](
Nan Zhoufe04d492022-06-22 17:10:41 +00002101 const std::shared_ptr<std::set<std::string>>& sensorNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002102 BMCWEB_LOG_DEBUG("getChassisCb enter");
2103 processSensorList(sensorsAsyncResp, sensorNames);
2104 BMCWEB_LOG_DEBUG("getChassisCb exit");
2105 };
Nan Zhou928fefb2022-03-28 08:45:00 -07002106 // SensorCollection doesn't contain the Redundancy property
Janet Adkins0c728b42024-08-29 11:09:10 -05002107 if (sensorsAsyncResp->chassisSubNode != sensors::sensorsNodeStr)
Nan Zhou928fefb2022-03-28 08:45:00 -07002108 {
2109 sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
2110 nlohmann::json::array();
2111 }
Shawn McCarney26f03892019-05-03 13:20:24 -05002112 // Get set of sensors in chassis
Ed Tanous7f1cc262022-08-09 13:33:57 -07002113 getChassis(sensorsAsyncResp->asyncResp, sensorsAsyncResp->chassisId,
2114 sensorsAsyncResp->chassisSubNode, sensorsAsyncResp->types,
2115 std::move(getChassisCb));
Ed Tanous62598e32023-07-17 17:06:25 -07002116 BMCWEB_LOG_DEBUG("getChassisData exit");
Ed Tanous271584a2019-07-09 16:24:22 -07002117}
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002118
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302119/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002120 * @brief Find the requested sensorName in the list of all sensors supplied by
2121 * the chassis node
2122 *
2123 * @param sensorName The sensor name supplied in the PATCH request
2124 * @param sensorsList The list of sensors managed by the chassis node
2125 * @param sensorsModified The list of sensors that were found as a result of
2126 * repeated calls to this function
2127 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002128inline bool findSensorNameUsingSensorPath(
2129 std::string_view sensorName, const std::set<std::string>& sensorsList,
2130 std::set<std::string>& sensorsModified)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002131{
Nan Zhoufe04d492022-06-22 17:10:41 +00002132 for (const auto& chassisSensor : sensorsList)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002133 {
George Liu28aa8de2021-02-01 15:13:30 +08002134 sdbusplus::message::object_path path(chassisSensor);
Ed Tanousb00dcc22021-02-23 12:52:50 -08002135 std::string thisSensorName = path.filename();
George Liu28aa8de2021-02-01 15:13:30 +08002136 if (thisSensorName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002137 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002138 continue;
2139 }
2140 if (thisSensorName == sensorName)
2141 {
2142 sensorsModified.emplace(chassisSensor);
2143 return true;
2144 }
2145 }
2146 return false;
2147}
2148
2149/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302150 * @brief Entry point for overriding sensor values of given sensor
2151 *
zhanghch058d1b46d2021-04-01 11:18:24 +08002152 * @param sensorAsyncResp response object
Carol Wang4bb3dc32019-10-17 18:15:02 +08002153 * @param allCollections Collections extract from sensors' request patch info
jayaprakash Mutyala91e130a2020-03-04 22:26:38 +00002154 * @param chassisSubNode Chassis Node for which the query has to happen
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302155 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002156inline void setSensorsOverride(
Ed Tanousb5a76932020-09-29 16:16:58 -07002157 const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
Ed Tanous08850572024-03-06 15:09:17 -08002158 std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>&
jayaprakash Mutyala397fd612020-02-06 23:33:34 +00002159 allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302160{
Ed Tanous62598e32023-07-17 17:06:25 -07002161 BMCWEB_LOG_INFO("setSensorsOverride for subNode{}",
2162 sensorAsyncResp->chassisSubNode);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302163
Ed Tanousd02aad32024-02-13 14:43:34 -08002164 std::string_view propertyValueName;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302165 std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302166 std::string memberId;
Ed Tanous543f4402022-01-06 13:12:53 -08002167 double value = 0.0;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302168 for (auto& collectionItems : allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302169 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302170 if (collectionItems.first == "Temperatures")
2171 {
2172 propertyValueName = "ReadingCelsius";
2173 }
2174 else if (collectionItems.first == "Fans")
2175 {
2176 propertyValueName = "Reading";
2177 }
2178 else
2179 {
2180 propertyValueName = "ReadingVolts";
2181 }
2182 for (auto& item : collectionItems.second)
2183 {
Ed Tanous08850572024-03-06 15:09:17 -08002184 if (!json_util::readJsonObject(
2185 item, sensorAsyncResp->asyncResp->res, "MemberId", memberId,
2186 propertyValueName, value))
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302187 {
2188 return;
2189 }
2190 overrideMap.emplace(memberId,
2191 std::make_pair(value, collectionItems.first));
2192 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302193 }
Carol Wang4bb3dc32019-10-17 18:15:02 +08002194
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002195 auto getChassisSensorListCb = [sensorAsyncResp, overrideMap,
2196 propertyValueNameStr =
2197 std::string(propertyValueName)](
2198 const std::shared_ptr<
2199 std::set<std::string>>& sensorsList) {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002200 // Match sensor names in the PATCH request to those managed by the
2201 // chassis node
Nan Zhoufe04d492022-06-22 17:10:41 +00002202 const std::shared_ptr<std::set<std::string>> sensorNames =
2203 std::make_shared<std::set<std::string>>();
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302204 for (const auto& item : overrideMap)
2205 {
2206 const auto& sensor = item.first;
Ed Tanousc71d6122022-11-29 14:10:32 -08002207 std::pair<std::string, std::string> sensorNameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002208 redfish::sensor_utils::splitSensorNameAndType(sensor);
Ed Tanousc71d6122022-11-29 14:10:32 -08002209 if (!findSensorNameUsingSensorPath(sensorNameType.second,
2210 *sensorsList, *sensorNames))
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302211 {
Ed Tanous62598e32023-07-17 17:06:25 -07002212 BMCWEB_LOG_INFO("Unable to find memberId {}", item.first);
zhanghch058d1b46d2021-04-01 11:18:24 +08002213 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302214 item.second.second, item.first);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302215 return;
2216 }
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302217 }
2218 // Get the connection to which the memberId belongs
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002219 auto getObjectsWithConnectionCb = [sensorAsyncResp, overrideMap,
2220 propertyValueNameStr](
2221 const std::set<
2222 std::string>& /*connections*/,
2223 const std::set<std::pair<
2224 std::string, std::string>>&
2225 objectsWithConnection) {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002226 if (objectsWithConnection.size() != overrideMap.size())
2227 {
Ed Tanous62598e32023-07-17 17:06:25 -07002228 BMCWEB_LOG_INFO(
2229 "Unable to find all objects with proper connection {} requested {}",
2230 objectsWithConnection.size(), overrideMap.size());
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002231 messages::resourceNotFound(
2232 sensorAsyncResp->asyncResp->res,
Janet Adkins0c728b42024-08-29 11:09:10 -05002233 sensorAsyncResp->chassisSubNode == sensors::thermalNodeStr
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002234 ? "Temperatures"
2235 : "Voltages",
2236 "Count");
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002237 return;
2238 }
2239 for (const auto& item : objectsWithConnection)
2240 {
2241 sdbusplus::message::object_path path(item.first);
2242 std::string sensorName = path.filename();
2243 if (sensorName.empty())
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302244 {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002245 messages::internalError(sensorAsyncResp->asyncResp->res);
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302246 return;
2247 }
Janet Adkins1516c212024-08-14 13:22:41 -05002248 std::string id = redfish::sensor_utils::getSensorId(
2249 sensorName, path.parent_path().filename());
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302250
Ban Feng3f5eb752023-06-29 09:19:20 +08002251 const auto& iterator = overrideMap.find(id);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002252 if (iterator == overrideMap.end())
2253 {
Ed Tanous62598e32023-07-17 17:06:25 -07002254 BMCWEB_LOG_INFO("Unable to find sensor object{}",
2255 item.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002256 messages::internalError(sensorAsyncResp->asyncResp->res);
2257 return;
2258 }
Ginu Georgee93abac2024-06-14 17:35:27 +05302259 setDbusProperty(sensorAsyncResp->asyncResp,
2260 propertyValueNameStr, item.second, item.first,
2261 "xyz.openbmc_project.Sensor.Value", "Value",
Ed Tanousd02aad32024-02-13 14:43:34 -08002262 iterator->second.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002263 }
2264 };
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302265 // Get object with connection for the given sensor name
2266 getObjectsWithConnection(sensorAsyncResp, sensorNames,
2267 std::move(getObjectsWithConnectionCb));
2268 };
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302269 // get full sensor list for the given chassisId and cross verify the sensor.
Ed Tanous7f1cc262022-08-09 13:33:57 -07002270 getChassis(sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId,
2271 sensorAsyncResp->chassisSubNode, sensorAsyncResp->types,
2272 std::move(getChassisSensorListCb));
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302273}
2274
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002275/**
2276 * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus
2277 * path of the sensor.
2278 *
2279 * Function builds valid Redfish response for sensor query of given chassis and
2280 * node. It then builds metadata about Redfish<->D-Bus correlations and provides
2281 * it to caller in a callback.
2282 *
2283 * @param chassis Chassis for which retrieval should be performed
Janet Adkinsc9563602024-08-28 11:37:46 -05002284 * @param node Node (group) of sensors. See sensor_utils::node for supported
2285 * values
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002286 * @param mapComplete Callback to be called with retrieval result
2287 */
Ed Tanous931edc72023-11-01 12:09:07 -07002288template <typename Callback>
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002289inline void retrieveUriToDbusMap(
2290 const std::string& chassis, const std::string& node, Callback&& mapComplete)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002291{
Ed Tanous02da7c52022-02-27 00:09:02 -08002292 decltype(sensors::paths)::const_iterator pathIt =
2293 std::find_if(sensors::paths.cbegin(), sensors::paths.cend(),
2294 [&node](auto&& val) { return val.first == node; });
2295 if (pathIt == sensors::paths.cend())
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002296 {
Ed Tanous62598e32023-07-17 17:06:25 -07002297 BMCWEB_LOG_ERROR("Wrong node provided : {}", node);
Ed Tanous6804b5c2023-10-31 14:50:03 -07002298 std::map<std::string, std::string> noop;
2299 mapComplete(boost::beast::http::status::bad_request, noop);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002300 return;
2301 }
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002302
Nan Zhou72374eb2022-01-27 17:06:51 -08002303 auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002304 auto callback =
2305 [asyncResp, mapCompleteCb = std::forward<Callback>(mapComplete)](
2306 const boost::beast::http::status status,
2307 const std::map<std::string, std::string>& uriToDbus) {
2308 mapCompleteCb(status, uriToDbus);
2309 };
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002310
2311 auto resp = std::make_shared<SensorsAsyncResp>(
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002312 asyncResp, chassis, pathIt->second, node, std::move(callback));
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002313 getChassisData(resp);
2314}
2315
Nan Zhoubacb2162022-04-06 11:28:32 -07002316namespace sensors
2317{
Nan Zhou928fefb2022-03-28 08:45:00 -07002318
Nan Zhoubacb2162022-04-06 11:28:32 -07002319inline void getChassisCallback(
Ed Tanousc1d019a2022-08-06 09:36:06 -07002320 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2321 std::string_view chassisId, std::string_view chassisSubNode,
Nan Zhoufe04d492022-06-22 17:10:41 +00002322 const std::shared_ptr<std::set<std::string>>& sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002323{
Ed Tanous62598e32023-07-17 17:06:25 -07002324 BMCWEB_LOG_DEBUG("getChassisCallback enter ");
Nan Zhoubacb2162022-04-06 11:28:32 -07002325
Ed Tanousc1d019a2022-08-06 09:36:06 -07002326 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
2327 for (const std::string& sensor : *sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002328 {
Ed Tanous62598e32023-07-17 17:06:25 -07002329 BMCWEB_LOG_DEBUG("Adding sensor: {}", sensor);
Nan Zhoubacb2162022-04-06 11:28:32 -07002330
2331 sdbusplus::message::object_path path(sensor);
2332 std::string sensorName = path.filename();
2333 if (sensorName.empty())
2334 {
Ed Tanous62598e32023-07-17 17:06:25 -07002335 BMCWEB_LOG_ERROR("Invalid sensor path: {}", sensor);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002336 messages::internalError(asyncResp->res);
Nan Zhoubacb2162022-04-06 11:28:32 -07002337 return;
2338 }
Ed Tanousc1d019a2022-08-06 09:36:06 -07002339 std::string type = path.parent_path().filename();
Janet Adkins1516c212024-08-14 13:22:41 -05002340 std::string id = redfish::sensor_utils::getSensorId(sensorName, type);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002341
Ed Tanous14766872022-03-15 10:44:42 -07002342 nlohmann::json::object_t member;
Ed Tanousef4c65b2023-04-24 15:28:50 -07002343 member["@odata.id"] = boost::urls::format(
2344 "/redfish/v1/Chassis/{}/{}/{}", chassisId, chassisSubNode, id);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002345
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002346 entriesArray.emplace_back(std::move(member));
Nan Zhoubacb2162022-04-06 11:28:32 -07002347 }
2348
Ed Tanousc1d019a2022-08-06 09:36:06 -07002349 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Ed Tanous62598e32023-07-17 17:06:25 -07002350 BMCWEB_LOG_DEBUG("getChassisCallback exit");
Nan Zhoubacb2162022-04-06 11:28:32 -07002351}
Nan Zhoue6bd8462022-06-01 04:35:35 +00002352
Ed Tanousac106bf2023-06-07 09:24:59 -07002353inline void handleSensorCollectionGet(
2354 App& app, const crow::Request& req,
2355 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2356 const std::string& chassisId)
Nan Zhoude167a62022-06-01 04:47:45 +00002357{
2358 query_param::QueryCapabilities capabilities = {
2359 .canDelegateExpandLevel = 1,
2360 };
2361 query_param::Query delegatedQuery;
Ed Tanousac106bf2023-06-07 09:24:59 -07002362 if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
Nan Zhoude167a62022-06-01 04:47:45 +00002363 delegatedQuery, capabilities))
2364 {
2365 return;
2366 }
2367
2368 if (delegatedQuery.expandType != query_param::ExpandType::None)
2369 {
2370 // we perform efficient expand.
Ed Tanousac106bf2023-06-07 09:24:59 -07002371 auto sensorsAsyncResp = std::make_shared<SensorsAsyncResp>(
2372 asyncResp, chassisId, sensors::dbus::sensorPaths,
Janet Adkins0c728b42024-08-29 11:09:10 -05002373 sensors::sensorsNodeStr,
Nan Zhoude167a62022-06-01 04:47:45 +00002374 /*efficientExpand=*/true);
Ed Tanousac106bf2023-06-07 09:24:59 -07002375 getChassisData(sensorsAsyncResp);
Nan Zhoude167a62022-06-01 04:47:45 +00002376
Ed Tanous62598e32023-07-17 17:06:25 -07002377 BMCWEB_LOG_DEBUG(
2378 "SensorCollection doGet exit via efficient expand handler");
Nan Zhoude167a62022-06-01 04:47:45 +00002379 return;
Ed Tanous0bad3202022-06-02 13:53:59 -07002380 }
Nan Zhoude167a62022-06-01 04:47:45 +00002381
Nan Zhoude167a62022-06-01 04:47:45 +00002382 // We get all sensors as hyperlinkes in the chassis (this
2383 // implies we reply on the default query parameters handler)
Janet Adkins0c728b42024-08-29 11:09:10 -05002384 getChassis(asyncResp, chassisId, sensors::sensorsNodeStr, dbus::sensorPaths,
Ed Tanousac106bf2023-06-07 09:24:59 -07002385 std::bind_front(sensors::getChassisCallback, asyncResp,
Janet Adkins0c728b42024-08-29 11:09:10 -05002386 chassisId, sensors::sensorsNodeStr));
Ed Tanousc1d019a2022-08-06 09:36:06 -07002387}
Ed Tanous7f1cc262022-08-09 13:33:57 -07002388
Ed Tanousc1d019a2022-08-06 09:36:06 -07002389inline void
2390 getSensorFromDbus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2391 const std::string& sensorPath,
2392 const ::dbus::utility::MapperGetObject& mapperResponse)
2393{
2394 if (mapperResponse.size() != 1)
2395 {
2396 messages::internalError(asyncResp->res);
2397 return;
2398 }
2399 const auto& valueIface = *mapperResponse.begin();
2400 const std::string& connectionName = valueIface.first;
Ed Tanous62598e32023-07-17 17:06:25 -07002401 BMCWEB_LOG_DEBUG("Looking up {}", connectionName);
2402 BMCWEB_LOG_DEBUG("Path {}", sensorPath);
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +02002403
2404 sdbusplus::asio::getAllProperties(
2405 *crow::connections::systemBus, connectionName, sensorPath, "",
Ed Tanousc1d019a2022-08-06 09:36:06 -07002406 [asyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002407 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002408 const ::dbus::utility::DBusPropertiesMap& valuesDict) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002409 if (ec)
2410 {
2411 messages::internalError(asyncResp->res);
2412 return;
2413 }
2414 sdbusplus::message::object_path path(sensorPath);
2415 std::string name = path.filename();
2416 path = path.parent_path();
2417 std::string type = path.filename();
Janet Adkinsc9563602024-08-28 11:37:46 -05002418 sensor_utils::objectPropertiesToJson(
Janet Adkins0c728b42024-08-29 11:09:10 -05002419 name, type, sensor_utils::ChassisSubNode::sensorsNode,
2420 valuesDict, asyncResp->res.jsonValue, nullptr);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002421 });
Nan Zhoude167a62022-06-01 04:47:45 +00002422}
2423
Nan Zhoue6bd8462022-06-01 04:35:35 +00002424inline void handleSensorGet(App& app, const crow::Request& req,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002425 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous677bb752022-09-15 10:52:19 -07002426 const std::string& chassisId,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002427 const std::string& sensorId)
Nan Zhoue6bd8462022-06-01 04:35:35 +00002428{
Ed Tanousc1d019a2022-08-06 09:36:06 -07002429 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Nan Zhoue6bd8462022-06-01 04:35:35 +00002430 {
2431 return;
2432 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002433 std::pair<std::string, std::string> nameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002434 redfish::sensor_utils::splitSensorNameAndType(sensorId);
Ed Tanousc71d6122022-11-29 14:10:32 -08002435 if (nameType.first.empty() || nameType.second.empty())
Ed Tanousc1d019a2022-08-06 09:36:06 -07002436 {
2437 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2438 return;
2439 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002440
Ed Tanousef4c65b2023-04-24 15:28:50 -07002441 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2442 "/redfish/v1/Chassis/{}/Sensors/{}", chassisId, sensorId);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002443
Ed Tanous62598e32023-07-17 17:06:25 -07002444 BMCWEB_LOG_DEBUG("Sensor doGet enter");
Nan Zhoue6bd8462022-06-01 04:35:35 +00002445
George Liu2b731192023-01-11 16:27:13 +08002446 constexpr std::array<std::string_view, 1> interfaces = {
Nan Zhoue6bd8462022-06-01 04:35:35 +00002447 "xyz.openbmc_project.Sensor.Value"};
Ed Tanousc71d6122022-11-29 14:10:32 -08002448 std::string sensorPath = "/xyz/openbmc_project/sensors/" + nameType.first +
2449 '/' + nameType.second;
Nan Zhoue6bd8462022-06-01 04:35:35 +00002450 // Get a list of all of the sensors that implement Sensor.Value
2451 // and get the path and service name associated with the sensor
George Liu2b731192023-01-11 16:27:13 +08002452 ::dbus::utility::getDbusObject(
2453 sensorPath, interfaces,
Myung Baeaec0ec32023-05-31 15:10:01 -05002454 [asyncResp, sensorId,
George Liu2b731192023-01-11 16:27:13 +08002455 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002456 const ::dbus::utility::MapperGetObject& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002457 BMCWEB_LOG_DEBUG("respHandler1 enter");
2458 if (ec == boost::system::errc::io_error)
2459 {
2460 BMCWEB_LOG_WARNING("Sensor not found from getSensorPaths");
2461 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2462 return;
2463 }
2464 if (ec)
2465 {
2466 messages::internalError(asyncResp->res);
2467 BMCWEB_LOG_ERROR(
2468 "Sensor getSensorPaths resp_handler: Dbus error {}", ec);
2469 return;
2470 }
2471 getSensorFromDbus(asyncResp, sensorPath, subtree);
2472 BMCWEB_LOG_DEBUG("respHandler1 exit");
2473 });
Nan Zhoue6bd8462022-06-01 04:35:35 +00002474}
2475
Nan Zhoubacb2162022-04-06 11:28:32 -07002476} // namespace sensors
2477
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002478inline void requestRoutesSensorCollection(App& app)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002479{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002480 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
Ed Tanoused398212021-06-09 17:05:54 -07002481 .privileges(redfish::privileges::getSensorCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002482 .methods(boost::beast::http::verb::get)(
Nan Zhoude167a62022-06-01 04:47:45 +00002483 std::bind_front(sensors::handleSensorCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002484}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002485
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002486inline void requestRoutesSensor(App& app)
2487{
2488 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002489 .privileges(redfish::privileges::getSensor)
Ed Tanous002d39b2022-05-31 08:59:27 -07002490 .methods(boost::beast::http::verb::get)(
Nan Zhoue6bd8462022-06-01 04:35:35 +00002491 std::bind_front(sensors::handleSensorGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002492}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002493
Ed Tanous1abe55e2018-09-05 08:30:59 -07002494} // namespace redfish