blob: 75ec8b926c5bc36f505696587b9406b176328324 [file] [log] [blame]
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
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>
968static void 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>
1057static void 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>
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001140static void 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 Tanousd0090732022-10-04 17:22:56 -07001673static void
1674 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