blob: 367f0d061bad2bc32ae6cfe5b729ad259d01c908 [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
Ed Tanouscf9e4172022-12-21 09:30:16 -080096using sensorPair =
97 std::pair<std::string_view, std::span<const std::string_view>>;
Ed Tanous02da7c52022-02-27 00:09:02 -080098static constexpr std::array<sensorPair, 3> paths = {
Janet Adkinsc9563602024-08-28 11:37:46 -050099 {{sensor_utils::powerNode, dbus::powerPaths},
100 {sensor_utils::sensorsNode, dbus::sensorPaths},
101 {sensor_utils::thermalNode, dbus::thermalPaths}}};
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000102
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200103} // namespace sensors
104
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100105/**
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200106 * SensorsAsyncResp
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100107 * Gathers data needed for response processing after async calls are done
108 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109class SensorsAsyncResp
110{
111 public:
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200112 using DataCompleteCb = std::function<void(
113 const boost::beast::http::status status,
Nan Zhoufe04d492022-06-22 17:10:41 +0000114 const std::map<std::string, std::string>& uriToDbus)>;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200115
116 struct SensorData
117 {
118 const std::string name;
119 std::string uri;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200120 const std::string dbusPath;
121 };
122
Ed Tanous8a592812022-06-04 09:06:59 -0700123 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800124 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800125 std::span<const std::string_view> typesIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800126 std::string_view subNode) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400127 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
128 chassisSubNode(subNode), efficientExpand(false)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500129 {}
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200130
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200131 // Store extra data about sensor mapping and return it in callback
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,
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200136 DataCompleteCb&& creationComplete) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400137 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
138 chassisSubNode(subNode), efficientExpand(false),
139 metadata{std::vector<SensorData>()},
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200140 dataComplete{std::move(creationComplete)}
141 {}
142
Nan Zhou928fefb2022-03-28 08:45:00 -0700143 // sensor collections expand
Ed Tanous8a592812022-06-04 09:06:59 -0700144 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
Nan Zhou928fefb2022-03-28 08:45:00 -0700145 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800146 std::span<const std::string_view> typesIn,
Ed Tanous8a592812022-06-04 09:06:59 -0700147 const std::string_view& subNode, bool efficientExpandIn) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400148 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
149 chassisSubNode(subNode), efficientExpand(efficientExpandIn)
Nan Zhou928fefb2022-03-28 08:45:00 -0700150 {}
151
Ed Tanous1abe55e2018-09-05 08:30:59 -0700152 ~SensorsAsyncResp()
153 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800154 if (asyncResp->res.result() ==
155 boost::beast::http::status::internal_server_error)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700156 {
157 // Reset the json object to clear out any data that made it in
158 // before the error happened todo(ed) handle error condition with
159 // proper code
zhanghch058d1b46d2021-04-01 11:18:24 +0800160 asyncResp->res.jsonValue = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700161 }
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200162
163 if (dataComplete && metadata)
164 {
Nan Zhoufe04d492022-06-22 17:10:41 +0000165 std::map<std::string, std::string> map;
zhanghch058d1b46d2021-04-01 11:18:24 +0800166 if (asyncResp->res.result() == boost::beast::http::status::ok)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200167 {
168 for (auto& sensor : *metadata)
169 {
Ed Tanousc1d019a2022-08-06 09:36:06 -0700170 map.emplace(sensor.uri, sensor.dbusPath);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200171 }
172 }
zhanghch058d1b46d2021-04-01 11:18:24 +0800173 dataComplete(asyncResp->res.result(), map);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200174 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700175 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100176
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800177 SensorsAsyncResp(const SensorsAsyncResp&) = delete;
178 SensorsAsyncResp(SensorsAsyncResp&&) = delete;
179 SensorsAsyncResp& operator=(const SensorsAsyncResp&) = delete;
180 SensorsAsyncResp& operator=(SensorsAsyncResp&&) = delete;
181
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200182 void addMetadata(const nlohmann::json& sensorObject,
Ed Tanousc1d019a2022-08-06 09:36:06 -0700183 const std::string& dbusPath)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200184 {
185 if (metadata)
186 {
Ed Tanousc1d019a2022-08-06 09:36:06 -0700187 metadata->emplace_back(SensorData{
188 sensorObject["Name"], sensorObject["@odata.id"], dbusPath});
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200189 }
190 }
191
192 void updateUri(const std::string& name, const std::string& uri)
193 {
194 if (metadata)
195 {
196 for (auto& sensor : *metadata)
197 {
198 if (sensor.name == name)
199 {
200 sensor.uri = uri;
201 }
202 }
203 }
204 }
205
zhanghch058d1b46d2021-04-01 11:18:24 +0800206 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200207 const std::string chassisId;
Ed Tanouscf9e4172022-12-21 09:30:16 -0800208 const std::span<const std::string_view> types;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200209 const std::string chassisSubNode;
Nan Zhou928fefb2022-03-28 08:45:00 -0700210 const bool efficientExpand;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200211
212 private:
213 std::optional<std::vector<SensorData>> metadata;
214 DataCompleteCb dataComplete;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100215};
216
Janet Adkinsc9563602024-08-28 11:37:46 -0500217using InventoryItem = sensor_utils::InventoryItem;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500218
219/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530220 * @brief Get objects with connection necessary for sensors
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200221 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100222 * @param sensorNames Sensors retrieved from chassis
223 * @param callback Callback for processing gathered connections
224 */
225template <typename Callback>
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530226void getObjectsWithConnection(
Ed Tanous81ce6092020-12-17 16:54:55 +0000227 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +0000228 const std::shared_ptr<std::set<std::string>>& sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530229 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700230{
Ed Tanous62598e32023-07-17 17:06:25 -0700231 BMCWEB_LOG_DEBUG("getObjectsWithConnection enter");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700232 const std::string path = "/xyz/openbmc_project/sensors";
George Liue99073f2022-12-09 11:06:16 +0800233 constexpr std::array<std::string_view, 1> interfaces = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700234 "xyz.openbmc_project.Sensor.Value"};
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100235
George Liue99073f2022-12-09 11:06:16 +0800236 // Make call to ObjectMapper to find all sensors objects
237 dbus::utility::getSubTree(
238 path, 2, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700239 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
George Liue99073f2022-12-09 11:06:16 +0800240 sensorNames](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700241 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400242 // Response handler for parsing objects subtree
243 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler enter");
244 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700245 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400246 messages::internalError(sensorsAsyncResp->asyncResp->res);
247 BMCWEB_LOG_ERROR(
248 "getObjectsWithConnection resp_handler: Dbus error {}", ec);
249 return;
250 }
251
252 BMCWEB_LOG_DEBUG("Found {} subtrees", subtree.size());
253
254 // Make unique list of connections only for requested sensor types
255 // and found in the chassis
256 std::set<std::string> connections;
257 std::set<std::pair<std::string, std::string>> objectsWithConnection;
258
259 BMCWEB_LOG_DEBUG("sensorNames list count: {}", sensorNames->size());
260 for (const std::string& tsensor : *sensorNames)
261 {
262 BMCWEB_LOG_DEBUG("Sensor to find: {}", tsensor);
263 }
264
265 for (const std::pair<std::string,
266 std::vector<std::pair<
267 std::string, std::vector<std::string>>>>&
268 object : subtree)
269 {
270 if (sensorNames->find(object.first) != sensorNames->end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700271 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400272 for (const std::pair<std::string, std::vector<std::string>>&
273 objData : object.second)
274 {
275 BMCWEB_LOG_DEBUG("Adding connection: {}",
276 objData.first);
277 connections.insert(objData.first);
278 objectsWithConnection.insert(
279 std::make_pair(object.first, objData.first));
280 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700281 }
282 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400283 BMCWEB_LOG_DEBUG("Found {} connections", connections.size());
284 callback(std::move(connections), std::move(objectsWithConnection));
285 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler exit");
286 });
Ed Tanous62598e32023-07-17 17:06:25 -0700287 BMCWEB_LOG_DEBUG("getObjectsWithConnection exit");
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530288}
289
290/**
291 * @brief Create connections necessary for sensors
292 * @param SensorsAsyncResp Pointer to object holding response data
293 * @param sensorNames Sensors retrieved from chassis
294 * @param callback Callback for processing gathered connections
295 */
296template <typename Callback>
Nan Zhoufe04d492022-06-22 17:10:41 +0000297void getConnections(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
298 const std::shared_ptr<std::set<std::string>> sensorNames,
299 Callback&& callback)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530300{
301 auto objectsWithConnectionCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -0700302 [callback = std::forward<Callback>(callback)](
303 const std::set<std::string>& connections,
304 const std::set<std::pair<std::string, std::string>>&
305 /*objectsWithConnection*/) { callback(connections); };
Ed Tanous81ce6092020-12-17 16:54:55 +0000306 getObjectsWithConnection(sensorsAsyncResp, sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530307 std::move(objectsWithConnectionCb));
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100308}
309
310/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700311 * @brief Shrinks the list of sensors for processing
312 * @param SensorsAysncResp The class holding the Redfish response
313 * @param allSensors A list of all the sensors associated to the
314 * chassis element (i.e. baseboard, front panel, etc...)
315 * @param activeSensors A list that is a reduction of the incoming
316 * allSensors list. Eliminate Thermal sensors when a Power request is
317 * made, and eliminate Power sensors when a Thermal request is made.
318 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000319inline void reduceSensorList(
Ed Tanous7f1cc262022-08-09 13:33:57 -0700320 crow::Response& res, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800321 std::span<const std::string_view> sensorTypes,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700322 const std::vector<std::string>* allSensors,
Nan Zhoufe04d492022-06-22 17:10:41 +0000323 const std::shared_ptr<std::set<std::string>>& activeSensors)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700324{
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700325 if ((allSensors == nullptr) || (activeSensors == nullptr))
326 {
Ed Tanous7f1cc262022-08-09 13:33:57 -0700327 messages::resourceNotFound(res, chassisSubNode,
Janet Adkinsc9563602024-08-28 11:37:46 -0500328 chassisSubNode == sensor_utils::thermalNode
Ed Tanous7f1cc262022-08-09 13:33:57 -0700329 ? "Temperatures"
330 : "Voltages");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700331
332 return;
333 }
334 if (allSensors->empty())
335 {
336 // Nothing to do, the activeSensors object is also empty
337 return;
338 }
339
Ed Tanous7f1cc262022-08-09 13:33:57 -0700340 for (std::string_view type : sensorTypes)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700341 {
342 for (const std::string& sensor : *allSensors)
343 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700344 if (sensor.starts_with(type))
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700345 {
346 activeSensors->emplace(sensor);
347 }
348 }
349 }
350}
351
Ed Tanous7f1cc262022-08-09 13:33:57 -0700352/*
353 *Populates the top level collection for a given subnode. Populates
354 *SensorCollection, Power, or Thermal schemas.
355 *
356 * */
357inline void populateChassisNode(nlohmann::json& jsonValue,
358 std::string_view chassisSubNode)
359{
Janet Adkinsc9563602024-08-28 11:37:46 -0500360 if (chassisSubNode == sensor_utils::powerNode)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700361 {
362 jsonValue["@odata.type"] = "#Power.v1_5_2.Power";
363 }
Janet Adkinsc9563602024-08-28 11:37:46 -0500364 else if (chassisSubNode == sensor_utils::thermalNode)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700365 {
366 jsonValue["@odata.type"] = "#Thermal.v1_4_0.Thermal";
367 jsonValue["Fans"] = nlohmann::json::array();
368 jsonValue["Temperatures"] = nlohmann::json::array();
369 }
Janet Adkinsc9563602024-08-28 11:37:46 -0500370 else if (chassisSubNode == sensor_utils::sensorsNode)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700371 {
372 jsonValue["@odata.type"] = "#SensorCollection.SensorCollection";
373 jsonValue["Description"] = "Collection of Sensors for this Chassis";
374 jsonValue["Members"] = nlohmann::json::array();
375 jsonValue["Members@odata.count"] = 0;
376 }
377
Janet Adkinsc9563602024-08-28 11:37:46 -0500378 if (chassisSubNode != sensor_utils::sensorsNode)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700379 {
380 jsonValue["Id"] = chassisSubNode;
381 }
382 jsonValue["Name"] = chassisSubNode;
383}
384
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700385/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100386 * @brief Retrieves requested chassis sensors and redundancy data from DBus .
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200387 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100388 * @param callback Callback for next step in gathered sensor processing
389 */
390template <typename Callback>
Ed Tanous7f1cc262022-08-09 13:33:57 -0700391void getChassis(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
392 std::string_view chassisId, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800393 std::span<const std::string_view> sensorTypes,
394 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700395{
Ed Tanous62598e32023-07-17 17:06:25 -0700396 BMCWEB_LOG_DEBUG("getChassis enter");
George Liu7a1dbc42022-12-07 16:03:22 +0800397 constexpr std::array<std::string_view, 2> interfaces = {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700398 "xyz.openbmc_project.Inventory.Item.Board",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500399 "xyz.openbmc_project.Inventory.Item.Chassis"};
George Liu7a1dbc42022-12-07 16:03:22 +0800400
401 // Get the Chassis Collection
402 dbus::utility::getSubTreePaths(
403 "/xyz/openbmc_project/inventory", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700404 [callback = std::forward<Callback>(callback), asyncResp,
Ed Tanous7f1cc262022-08-09 13:33:57 -0700405 chassisIdStr{std::string(chassisId)},
406 chassisSubNode{std::string(chassisSubNode)}, sensorTypes](
George Liu7a1dbc42022-12-07 16:03:22 +0800407 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700408 const dbus::utility::MapperGetSubTreePathsResponse& chassisPaths) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400409 BMCWEB_LOG_DEBUG("getChassis respHandler enter");
410 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700411 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400412 BMCWEB_LOG_ERROR("getChassis respHandler DBUS error: {}", ec);
413 messages::internalError(asyncResp->res);
414 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700415 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400416 const std::string* chassisPath = nullptr;
417 for (const std::string& chassis : chassisPaths)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700418 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400419 sdbusplus::message::object_path path(chassis);
420 std::string chassisName = path.filename();
421 if (chassisName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700422 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400423 BMCWEB_LOG_ERROR("Failed to find '/' in {}", chassis);
424 continue;
425 }
426 if (chassisName == chassisIdStr)
427 {
428 chassisPath = &chassis;
429 break;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700430 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700431 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400432 if (chassisPath == nullptr)
433 {
434 messages::resourceNotFound(asyncResp->res, "Chassis",
435 chassisIdStr);
436 return;
437 }
438 populateChassisNode(asyncResp->res.jsonValue, chassisSubNode);
439
440 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
441 "/redfish/v1/Chassis/{}/{}", chassisIdStr, chassisSubNode);
442
443 // Get the list of all sensors for this Chassis element
444 std::string sensorPath = *chassisPath + "/all_sensors";
445 dbus::utility::getAssociationEndPoints(
446 sensorPath,
447 [asyncResp, chassisSubNode, sensorTypes,
448 callback = std::forward<const Callback>(callback)](
449 const boost::system::error_code& ec2,
450 const dbus::utility::MapperEndPoints& nodeSensorList) {
451 if (ec2)
452 {
453 if (ec2.value() != EBADR)
454 {
455 messages::internalError(asyncResp->res);
456 return;
457 }
458 }
459 const std::shared_ptr<std::set<std::string>>
460 culledSensorList =
461 std::make_shared<std::set<std::string>>();
462 reduceSensorList(asyncResp->res, chassisSubNode,
463 sensorTypes, &nodeSensorList,
464 culledSensorList);
465 BMCWEB_LOG_DEBUG("Finishing with {}",
466 culledSensorList->size());
467 callback(culledSensorList);
468 });
George Liu7a1dbc42022-12-07 16:03:22 +0800469 });
Ed Tanous62598e32023-07-17 17:06:25 -0700470 BMCWEB_LOG_DEBUG("getChassis exit");
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100471}
472
473/**
Ed Tanous1d7c0052022-08-09 12:32:26 -0700474 * @brief Builds a json sensor representation of a sensor.
475 * @param sensorName The name of the sensor to be built
476 * @param sensorType The type (temperature, fan_tach, etc) of the sensor to
477 * build
Ed Tanous8ece0e42024-01-02 13:16:50 -0800478 * @param chassisSubNode The subnode (thermal, sensor, etc) of the sensor
Ed Tanous1d7c0052022-08-09 12:32:26 -0700479 * @param interfacesDict A dictionary of the interfaces and properties of said
480 * interfaces to be built from
481 * @param sensorJson The json object to fill
482 * @param inventoryItem D-Bus inventory item associated with the sensor. Will
483 * be nullptr if no associated inventory item was found.
484 */
485inline void objectInterfacesToJson(
486 const std::string& sensorName, const std::string& sensorType,
487 const std::string& chassisSubNode,
Michael Shen80f79a42023-08-24 13:41:53 +0000488 const dbus::utility::DBusInterfacesMap& interfacesDict,
Ed Tanous1d7c0052022-08-09 12:32:26 -0700489 nlohmann::json& sensorJson, InventoryItem* inventoryItem)
490{
Ed Tanous1d7c0052022-08-09 12:32:26 -0700491 for (const auto& [interface, valuesDict] : interfacesDict)
492 {
Janet Adkinsc9563602024-08-28 11:37:46 -0500493 sensor_utils::objectPropertiesToJson(
494 sensorName, sensorType, chassisSubNode, valuesDict, sensorJson,
495 inventoryItem);
Ed Tanous1d7c0052022-08-09 12:32:26 -0700496 }
Ed Tanous62598e32023-07-17 17:06:25 -0700497 BMCWEB_LOG_DEBUG("Added sensor {}", sensorName);
Ed Tanous1d7c0052022-08-09 12:32:26 -0700498}
499
Ed Tanousb5a76932020-09-29 16:16:58 -0700500inline void populateFanRedundancy(
501 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
James Feist8bd25cc2019-03-15 15:14:00 -0700502{
George Liue99073f2022-12-09 11:06:16 +0800503 constexpr std::array<std::string_view, 1> interfaces = {
504 "xyz.openbmc_project.Control.FanRedundancy"};
505 dbus::utility::getSubTree(
506 "/xyz/openbmc_project/control", 2, interfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800507 [sensorsAsyncResp](
George Liue99073f2022-12-09 11:06:16 +0800508 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800509 const dbus::utility::MapperGetSubTreeResponse& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400510 if (ec)
James Feist8bd25cc2019-03-15 15:14:00 -0700511 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400512 return; // don't have to have this interface
James Feist8bd25cc2019-03-15 15:14:00 -0700513 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400514 for (const std::pair<std::string, dbus::utility::MapperServiceMap>&
515 pathPair : resp)
516 {
517 const std::string& path = pathPair.first;
518 const dbus::utility::MapperServiceMap& objDict =
519 pathPair.second;
520 if (objDict.empty())
James Feist8bd25cc2019-03-15 15:14:00 -0700521 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400522 continue; // this should be impossible
James Feist8bd25cc2019-03-15 15:14:00 -0700523 }
524
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400525 const std::string& owner = objDict.begin()->first;
526 dbus::utility::getAssociationEndPoints(
527 path + "/chassis",
528 [path, owner, sensorsAsyncResp](
529 const boost::system::error_code& ec2,
530 const dbus::utility::MapperEndPoints& endpoints) {
531 if (ec2)
James Feist8bd25cc2019-03-15 15:14:00 -0700532 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400533 return; // if they don't have an association we
534 // can't tell what chassis is
James Feist8bd25cc2019-03-15 15:14:00 -0700535 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400536 auto found = std::ranges::find_if(
537 endpoints,
538 [sensorsAsyncResp](const std::string& entry) {
539 return entry.find(
540 sensorsAsyncResp->chassisId) !=
541 std::string::npos;
542 });
543
544 if (found == endpoints.end())
James Feist8bd25cc2019-03-15 15:14:00 -0700545 {
546 return;
547 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400548 sdbusplus::asio::getAllProperties(
549 *crow::connections::systemBus, owner, path,
550 "xyz.openbmc_project.Control.FanRedundancy",
551 [path, sensorsAsyncResp](
552 const boost::system::error_code& ec3,
553 const dbus::utility::DBusPropertiesMap& ret) {
554 if (ec3)
555 {
556 return; // don't have to have this
557 // interface
558 }
James Feist8bd25cc2019-03-15 15:14:00 -0700559
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400560 const uint8_t* allowedFailures = nullptr;
561 const std::vector<std::string>* collection =
562 nullptr;
563 const std::string* status = nullptr;
James Feist8bd25cc2019-03-15 15:14:00 -0700564
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400565 const bool success =
566 sdbusplus::unpackPropertiesNoThrow(
567 dbus_utils::UnpackErrorPrinter(), ret,
568 "AllowedFailures", allowedFailures,
569 "Collection", collection, "Status",
570 status);
James Feist8bd25cc2019-03-15 15:14:00 -0700571
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400572 if (!success)
573 {
574 messages::internalError(
575 sensorsAsyncResp->asyncResp->res);
576 return;
577 }
578
579 if (allowedFailures == nullptr ||
580 collection == nullptr || status == nullptr)
581 {
582 BMCWEB_LOG_ERROR(
583 "Invalid redundancy interface");
584 messages::internalError(
585 sensorsAsyncResp->asyncResp->res);
586 return;
587 }
588
589 sdbusplus::message::object_path objectPath(
590 path);
591 std::string name = objectPath.filename();
592 if (name.empty())
593 {
594 // this should be impossible
595 messages::internalError(
596 sensorsAsyncResp->asyncResp->res);
597 return;
598 }
599 std::ranges::replace(name, '_', ' ');
600
601 std::string health;
602
603 if (status->ends_with("Full"))
604 {
605 health = "OK";
606 }
607 else if (status->ends_with("Degraded"))
608 {
609 health = "Warning";
610 }
611 else
612 {
613 health = "Critical";
614 }
615 nlohmann::json::array_t redfishCollection;
616 const auto& fanRedfish =
617 sensorsAsyncResp->asyncResp->res
618 .jsonValue["Fans"];
619 for (const std::string& item : *collection)
620 {
621 sdbusplus::message::object_path itemPath(
622 item);
623 std::string itemName = itemPath.filename();
624 if (itemName.empty())
625 {
626 continue;
627 }
628 /*
629 todo(ed): merge patch that fixes the names
630 std::replace(itemName.begin(),
631 itemName.end(), '_', ' ');*/
632 auto schemaItem = std::ranges::find_if(
633 fanRedfish,
634 [itemName](const nlohmann::json& fan) {
635 return fan["Name"] == itemName;
636 });
637 if (schemaItem != fanRedfish.end())
638 {
639 nlohmann::json::object_t collectionId;
640 collectionId["@odata.id"] =
641 (*schemaItem)["@odata.id"];
642 redfishCollection.emplace_back(
643 std::move(collectionId));
644 }
645 else
646 {
647 BMCWEB_LOG_ERROR(
648 "failed to find fan in schema");
649 messages::internalError(
650 sensorsAsyncResp->asyncResp->res);
651 return;
652 }
653 }
654
655 size_t minNumNeeded =
656 collection->empty()
657 ? 0
658 : collection->size() - *allowedFailures;
659 nlohmann::json& jResp =
660 sensorsAsyncResp->asyncResp->res
661 .jsonValue["Redundancy"];
662
663 nlohmann::json::object_t redundancy;
664 boost::urls::url url = boost::urls::format(
665 "/redfish/v1/Chassis/{}/{}",
666 sensorsAsyncResp->chassisId,
667 sensorsAsyncResp->chassisSubNode);
668 url.set_fragment(
669 ("/Redundancy"_json_pointer / jResp.size())
670 .to_string());
671 redundancy["@odata.id"] = std::move(url);
672 redundancy["@odata.type"] =
673 "#Redundancy.v1_3_2.Redundancy";
674 redundancy["MinNumNeeded"] = minNumNeeded;
675 redundancy["Mode"] =
676 redundancy::RedundancyType::NPlusM;
677 redundancy["Name"] = name;
678 redundancy["RedundancySet"] = redfishCollection;
679 redundancy["Status"]["Health"] = health;
680 redundancy["Status"]["State"] =
681 resource::State::Enabled;
682
683 jResp.emplace_back(std::move(redundancy));
684 });
685 });
686 }
687 });
James Feist8bd25cc2019-03-15 15:14:00 -0700688}
689
Ed Tanousb5a76932020-09-29 16:16:58 -0700690inline void
Ed Tanous81ce6092020-12-17 16:54:55 +0000691 sortJSONResponse(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700692{
zhanghch058d1b46d2021-04-01 11:18:24 +0800693 nlohmann::json& response = sensorsAsyncResp->asyncResp->res.jsonValue;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700694 std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
Janet Adkinsc9563602024-08-28 11:37:46 -0500695 if (sensorsAsyncResp->chassisSubNode == sensor_utils::powerNode)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700696 {
697 sensorHeaders = {"Voltages", "PowerSupplies"};
698 }
699 for (const std::string& sensorGroup : sensorHeaders)
700 {
701 nlohmann::json::iterator entry = response.find(sensorGroup);
702 if (entry != response.end())
703 {
704 std::sort(entry->begin(), entry->end(),
Ed Tanous02cad962022-06-30 16:50:15 -0700705 [](const nlohmann::json& c1, const nlohmann::json& c2) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400706 return c1["Name"] < c2["Name"];
707 });
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700708
709 // add the index counts to the end of each entry
710 size_t count = 0;
711 for (nlohmann::json& sensorJson : *entry)
712 {
713 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
714 if (odata == sensorJson.end())
715 {
716 continue;
717 }
718 std::string* value = odata->get_ptr<std::string*>();
719 if (value != nullptr)
720 {
Willy Tueddfc432022-09-26 16:46:38 +0000721 *value += "/" + std::to_string(count);
George Liu3e35c762023-03-08 16:56:38 +0800722 sensorJson["MemberId"] = std::to_string(count);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700723 count++;
Ed Tanous81ce6092020-12-17 16:54:55 +0000724 sensorsAsyncResp->updateUri(sensorJson["Name"], *value);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700725 }
726 }
727 }
728 }
729}
730
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100731/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500732 * @brief Finds the inventory item with the specified object path.
733 * @param inventoryItems D-Bus inventory items associated with sensors.
734 * @param invItemObjPath D-Bus object path of inventory item.
735 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500736 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000737inline InventoryItem* findInventoryItem(
Ed Tanousb5a76932020-09-29 16:16:58 -0700738 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500739 const std::string& invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500740{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500741 for (InventoryItem& inventoryItem : *inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500742 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500743 if (inventoryItem.objectPath == invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500744 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500745 return &inventoryItem;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500746 }
747 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500748 return nullptr;
749}
750
751/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500752 * @brief Finds the inventory item associated with the specified sensor.
753 * @param inventoryItems D-Bus inventory items associated with sensors.
754 * @param sensorObjPath D-Bus object path of sensor.
755 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500756 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000757inline InventoryItem* findInventoryItemForSensor(
Ed Tanousb5a76932020-09-29 16:16:58 -0700758 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500759 const std::string& sensorObjPath)
760{
761 for (InventoryItem& inventoryItem : *inventoryItems)
762 {
Ed Tanousdb0d36e2023-06-30 10:37:05 -0700763 if (inventoryItem.sensors.contains(sensorObjPath))
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500764 {
765 return &inventoryItem;
766 }
767 }
768 return nullptr;
769}
770
771/**
Anthony Wilsond5005492019-07-31 16:34:17 -0500772 * @brief Finds the inventory item associated with the specified led path.
773 * @param inventoryItems D-Bus inventory items associated with sensors.
774 * @param ledObjPath D-Bus object path of led.
775 * @return Inventory item within vector, or nullptr if no match found.
776 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400777inline InventoryItem* findInventoryItemForLed(
778 std::vector<InventoryItem>& inventoryItems, const std::string& ledObjPath)
Anthony Wilsond5005492019-07-31 16:34:17 -0500779{
780 for (InventoryItem& inventoryItem : inventoryItems)
781 {
782 if (inventoryItem.ledObjectPath == ledObjPath)
783 {
784 return &inventoryItem;
785 }
786 }
787 return nullptr;
788}
789
790/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500791 * @brief Adds inventory item and associated sensor to specified vector.
792 *
793 * Adds a new InventoryItem to the vector if necessary. Searches for an
794 * existing InventoryItem with the specified object path. If not found, one is
795 * added to the vector.
796 *
797 * Next, the specified sensor is added to the set of sensors associated with the
798 * InventoryItem.
799 *
800 * @param inventoryItems D-Bus inventory items associated with sensors.
801 * @param invItemObjPath D-Bus object path of inventory item.
802 * @param sensorObjPath D-Bus object path of sensor
803 */
Ed Tanousb5a76932020-09-29 16:16:58 -0700804inline void addInventoryItem(
805 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
806 const std::string& invItemObjPath, const std::string& sensorObjPath)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500807{
808 // Look for inventory item in vector
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400809 InventoryItem* inventoryItem =
810 findInventoryItem(inventoryItems, invItemObjPath);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500811
812 // If inventory item doesn't exist in vector, add it
813 if (inventoryItem == nullptr)
814 {
815 inventoryItems->emplace_back(invItemObjPath);
816 inventoryItem = &(inventoryItems->back());
817 }
818
819 // Add sensor to set of sensors associated with inventory item
820 inventoryItem->sensors.emplace(sensorObjPath);
821}
822
823/**
824 * @brief Stores D-Bus data in the specified inventory item.
825 *
826 * Finds D-Bus data in the specified map of interfaces. Stores the data in the
827 * specified InventoryItem.
828 *
829 * This data is later used to provide sensor property values in the JSON
830 * response.
831 *
832 * @param inventoryItem Inventory item where data will be stored.
833 * @param interfacesDict Map containing D-Bus interfaces and their properties
834 * for the specified inventory item.
835 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000836inline void storeInventoryItemData(
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500837 InventoryItem& inventoryItem,
Michael Shen80f79a42023-08-24 13:41:53 +0000838 const dbus::utility::DBusInterfacesMap& interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500839{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500840 // Get properties from Inventory.Item interface
Ed Tanous711ac7a2021-12-20 09:34:41 -0800841
Ed Tanous9eb808c2022-01-25 10:19:23 -0800842 for (const auto& [interface, values] : interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500843 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800844 if (interface == "xyz.openbmc_project.Inventory.Item")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500845 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800846 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500847 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800848 if (name == "Present")
849 {
850 const bool* value = std::get_if<bool>(&dbusValue);
851 if (value != nullptr)
852 {
853 inventoryItem.isPresent = *value;
854 }
855 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500856 }
857 }
Ed Tanous711ac7a2021-12-20 09:34:41 -0800858 // Check if Inventory.Item.PowerSupply interface is present
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500859
Ed Tanous711ac7a2021-12-20 09:34:41 -0800860 if (interface == "xyz.openbmc_project.Inventory.Item.PowerSupply")
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500861 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800862 inventoryItem.isPowerSupply = true;
863 }
864
865 // Get properties from Inventory.Decorator.Asset interface
866 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
867 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800868 for (const auto& [name, dbusValue] : values)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500869 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800870 if (name == "Manufacturer")
871 {
872 const std::string* value =
873 std::get_if<std::string>(&dbusValue);
874 if (value != nullptr)
875 {
876 inventoryItem.manufacturer = *value;
877 }
878 }
879 if (name == "Model")
880 {
881 const std::string* value =
882 std::get_if<std::string>(&dbusValue);
883 if (value != nullptr)
884 {
885 inventoryItem.model = *value;
886 }
887 }
888 if (name == "SerialNumber")
889 {
890 const std::string* value =
891 std::get_if<std::string>(&dbusValue);
892 if (value != nullptr)
893 {
894 inventoryItem.serialNumber = *value;
895 }
896 }
897 if (name == "PartNumber")
898 {
899 const std::string* value =
900 std::get_if<std::string>(&dbusValue);
901 if (value != nullptr)
902 {
903 inventoryItem.partNumber = *value;
904 }
905 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500906 }
907 }
908
Ed Tanous711ac7a2021-12-20 09:34:41 -0800909 if (interface ==
910 "xyz.openbmc_project.State.Decorator.OperationalStatus")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500911 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800912 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500913 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800914 if (name == "Functional")
915 {
916 const bool* value = std::get_if<bool>(&dbusValue);
917 if (value != nullptr)
918 {
919 inventoryItem.isFunctional = *value;
920 }
921 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500922 }
923 }
924 }
925}
926
927/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500928 * @brief Gets D-Bus data for inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500929 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500930 * Uses the specified connections (services) to obtain D-Bus data for inventory
931 * items associated with sensors. Stores the resulting data in the
932 * inventoryItems vector.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500933 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500934 * This data is later used to provide sensor property values in the JSON
935 * response.
936 *
937 * Finds the inventory item data asynchronously. Invokes callback when data has
938 * been obtained.
939 *
940 * The callback must have the following signature:
941 * @code
Anthony Wilsond5005492019-07-31 16:34:17 -0500942 * callback(void)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500943 * @endcode
944 *
945 * This function is called recursively, obtaining data asynchronously from one
946 * connection in each call. This ensures the callback is not invoked until the
947 * last asynchronous function has completed.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500948 *
949 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500950 * @param inventoryItems D-Bus inventory items associated with sensors.
951 * @param invConnections Connections that provide data for the inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500952 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500953 * @param callback Callback to invoke when inventory data has been obtained.
954 * @param invConnectionsIndex Current index in invConnections. Only specified
955 * in recursive calls to this function.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500956 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500957template <typename Callback>
958static void getInventoryItemsData(
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500959 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500960 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Ed Tanousd0090732022-10-04 17:22:56 -0700961 std::shared_ptr<std::set<std::string>> invConnections, Callback&& callback,
962 size_t invConnectionsIndex = 0)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500963{
Ed Tanous62598e32023-07-17 17:06:25 -0700964 BMCWEB_LOG_DEBUG("getInventoryItemsData enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500965
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500966 // If no more connections left, call callback
967 if (invConnectionsIndex >= invConnections->size())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500968 {
Anthony Wilsond5005492019-07-31 16:34:17 -0500969 callback();
Ed Tanous62598e32023-07-17 17:06:25 -0700970 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500971 return;
972 }
973
974 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +0000975 auto it = invConnections->begin();
976 std::advance(it, invConnectionsIndex);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500977 if (it != invConnections->end())
978 {
979 const std::string& invConnection = *it;
980
George Liu5eb468d2023-06-20 17:03:24 +0800981 // Get all object paths and their interfaces for current connection
982 sdbusplus::message::object_path path("/xyz/openbmc_project/inventory");
983 dbus::utility::getManagedObjects(
984 invConnection, path,
985 [sensorsAsyncResp, inventoryItems, invConnections,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700986 callback = std::forward<Callback>(callback), invConnectionsIndex](
George Liu5eb468d2023-06-20 17:03:24 +0800987 const boost::system::error_code& ec,
988 const dbus::utility::ManagedObjectType& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400989 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler enter");
990 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500991 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400992 BMCWEB_LOG_ERROR(
993 "getInventoryItemsData respHandler DBus error {}", ec);
994 messages::internalError(sensorsAsyncResp->asyncResp->res);
995 return;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500996 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500997
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400998 // Loop through returned object paths
999 for (const auto& objDictEntry : resp)
1000 {
1001 const std::string& objPath =
1002 static_cast<const std::string&>(objDictEntry.first);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001003
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001004 // If this object path is one of the specified inventory
1005 // items
1006 InventoryItem* inventoryItem =
1007 findInventoryItem(inventoryItems, objPath);
1008 if (inventoryItem != nullptr)
1009 {
1010 // Store inventory data in InventoryItem
1011 storeInventoryItemData(*inventoryItem,
1012 objDictEntry.second);
1013 }
1014 }
1015
1016 // Recurse to get inventory item data from next connection
1017 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1018 invConnections, std::move(callback),
1019 invConnectionsIndex + 1);
1020
1021 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler exit");
1022 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001023 }
1024
Ed Tanous62598e32023-07-17 17:06:25 -07001025 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001026}
1027
1028/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001029 * @brief Gets connections that provide D-Bus data for inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001030 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001031 * Gets the D-Bus connections (services) that provide data for the inventory
1032 * items that are associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001033 *
1034 * Finds the connections asynchronously. Invokes callback when information has
1035 * been obtained.
1036 *
1037 * The callback must have the following signature:
1038 * @code
Nan Zhoufe04d492022-06-22 17:10:41 +00001039 * callback(std::shared_ptr<std::set<std::string>> invConnections)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001040 * @endcode
1041 *
1042 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001043 * @param inventoryItems D-Bus inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001044 * @param callback Callback to invoke when connections have been obtained.
1045 */
1046template <typename Callback>
1047static void getInventoryItemsConnections(
Ed Tanousb5a76932020-09-29 16:16:58 -07001048 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1049 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001050 Callback&& callback)
1051{
Ed Tanous62598e32023-07-17 17:06:25 -07001052 BMCWEB_LOG_DEBUG("getInventoryItemsConnections enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001053
1054 const std::string path = "/xyz/openbmc_project/inventory";
George Liue99073f2022-12-09 11:06:16 +08001055 constexpr std::array<std::string_view, 4> interfaces = {
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001056 "xyz.openbmc_project.Inventory.Item",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001057 "xyz.openbmc_project.Inventory.Item.PowerSupply",
1058 "xyz.openbmc_project.Inventory.Decorator.Asset",
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001059 "xyz.openbmc_project.State.Decorator.OperationalStatus"};
1060
George Liue99073f2022-12-09 11:06:16 +08001061 // Make call to ObjectMapper to find all inventory items
1062 dbus::utility::getSubTree(
1063 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001064 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001065 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001066 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001067 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001068 // Response handler for parsing output from GetSubTree
1069 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler enter");
1070 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001071 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001072 messages::internalError(sensorsAsyncResp->asyncResp->res);
1073 BMCWEB_LOG_ERROR(
1074 "getInventoryItemsConnections respHandler DBus error {}",
1075 ec);
1076 return;
1077 }
1078
1079 // Make unique list of connections for desired inventory items
1080 std::shared_ptr<std::set<std::string>> invConnections =
1081 std::make_shared<std::set<std::string>>();
1082
1083 // Loop through objects from GetSubTree
1084 for (const std::pair<std::string,
1085 std::vector<std::pair<
1086 std::string, std::vector<std::string>>>>&
1087 object : subtree)
1088 {
1089 // Check if object path is one of the specified inventory items
1090 const std::string& objPath = object.first;
1091 if (findInventoryItem(inventoryItems, objPath) != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001092 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001093 // Store all connections to inventory item
1094 for (const std::pair<std::string, std::vector<std::string>>&
1095 objData : object.second)
1096 {
1097 const std::string& invConnection = objData.first;
1098 invConnections->insert(invConnection);
1099 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001100 }
1101 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001102
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001103 callback(invConnections);
1104 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler exit");
1105 });
Ed Tanous62598e32023-07-17 17:06:25 -07001106 BMCWEB_LOG_DEBUG("getInventoryItemsConnections exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001107}
1108
1109/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001110 * @brief Gets associations from sensors to inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001111 *
1112 * Looks for ObjectMapper associations from the specified sensors to related
Anthony Wilsond5005492019-07-31 16:34:17 -05001113 * inventory items. Then finds the associations from those inventory items to
1114 * their LEDs, if any.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001115 *
1116 * Finds the inventory items asynchronously. Invokes callback when information
1117 * has been obtained.
1118 *
1119 * The callback must have the following signature:
1120 * @code
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001121 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001122 * @endcode
1123 *
1124 * @param sensorsAsyncResp Pointer to object holding response data.
1125 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001126 * implements ObjectManager.
1127 * @param callback Callback to invoke when inventory items have been obtained.
1128 */
1129template <typename Callback>
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001130static void getInventoryItemAssociations(
Ed Tanousb5a76932020-09-29 16:16:58 -07001131 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001132 const std::shared_ptr<std::set<std::string>>& sensorNames,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001133 Callback&& callback)
1134{
Ed Tanous62598e32023-07-17 17:06:25 -07001135 BMCWEB_LOG_DEBUG("getInventoryItemAssociations enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001136
George Liu5eb468d2023-06-20 17:03:24 +08001137 // Call GetManagedObjects on the ObjectMapper to get all associations
1138 sdbusplus::message::object_path path("/");
1139 dbus::utility::getManagedObjects(
1140 "xyz.openbmc_project.ObjectMapper", path,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001141 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001142 sensorNames](const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -07001143 const dbus::utility::ManagedObjectType& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001144 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler enter");
1145 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001146 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001147 BMCWEB_LOG_ERROR(
1148 "getInventoryItemAssociations respHandler DBus error {}",
1149 ec);
1150 messages::internalError(sensorsAsyncResp->asyncResp->res);
1151 return;
1152 }
1153
1154 // Create vector to hold list of inventory items
1155 std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1156 std::make_shared<std::vector<InventoryItem>>();
1157
1158 // Loop through returned object paths
1159 std::string sensorAssocPath;
1160 sensorAssocPath.reserve(128); // avoid memory allocations
1161 for (const auto& objDictEntry : resp)
1162 {
1163 const std::string& objPath =
1164 static_cast<const std::string&>(objDictEntry.first);
1165
1166 // If path is inventory association for one of the specified
1167 // sensors
1168 for (const std::string& sensorName : *sensorNames)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001169 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001170 sensorAssocPath = sensorName;
1171 sensorAssocPath += "/inventory";
1172 if (objPath == sensorAssocPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001173 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001174 // Get Association interface for object path
1175 for (const auto& [interface, values] :
1176 objDictEntry.second)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001177 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001178 if (interface == "xyz.openbmc_project.Association")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001179 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001180 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001181 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001182 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001183 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001184 const std::vector<std::string>*
1185 endpoints = std::get_if<
1186 std::vector<std::string>>(
1187 &value);
1188 if ((endpoints != nullptr) &&
1189 !endpoints->empty())
1190 {
1191 // Add inventory item to vector
1192 const std::string& invItemPath =
1193 endpoints->front();
1194 addInventoryItem(inventoryItems,
1195 invItemPath,
1196 sensorName);
1197 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001198 }
1199 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001200 }
1201 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001202 break;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001203 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001204 }
1205 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001206
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001207 // Now loop through the returned object paths again, this time to
1208 // find the leds associated with the inventory items we just found
1209 std::string inventoryAssocPath;
1210 inventoryAssocPath.reserve(128); // avoid memory allocations
1211 for (const auto& objDictEntry : resp)
Anthony Wilsond5005492019-07-31 16:34:17 -05001212 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001213 const std::string& objPath =
1214 static_cast<const std::string&>(objDictEntry.first);
1215
1216 for (InventoryItem& inventoryItem : *inventoryItems)
Anthony Wilsond5005492019-07-31 16:34:17 -05001217 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001218 inventoryAssocPath = inventoryItem.objectPath;
1219 inventoryAssocPath += "/leds";
1220 if (objPath == inventoryAssocPath)
Anthony Wilsond5005492019-07-31 16:34:17 -05001221 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001222 for (const auto& [interface, values] :
1223 objDictEntry.second)
Anthony Wilsond5005492019-07-31 16:34:17 -05001224 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001225 if (interface == "xyz.openbmc_project.Association")
Anthony Wilsond5005492019-07-31 16:34:17 -05001226 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001227 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001228 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001229 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001230 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001231 const std::vector<std::string>*
1232 endpoints = std::get_if<
1233 std::vector<std::string>>(
1234 &value);
1235 if ((endpoints != nullptr) &&
1236 !endpoints->empty())
1237 {
1238 // Add inventory item to vector
1239 // Store LED path in inventory item
1240 const std::string& ledPath =
1241 endpoints->front();
1242 inventoryItem.ledObjectPath =
1243 ledPath;
1244 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001245 }
1246 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001247 }
1248 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001249
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001250 break;
1251 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001252 }
1253 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001254 callback(inventoryItems);
1255 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler exit");
1256 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001257
Ed Tanous62598e32023-07-17 17:06:25 -07001258 BMCWEB_LOG_DEBUG("getInventoryItemAssociations exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001259}
1260
1261/**
Anthony Wilsond5005492019-07-31 16:34:17 -05001262 * @brief Gets D-Bus data for inventory item leds associated with sensors.
1263 *
1264 * Uses the specified connections (services) to obtain D-Bus data for inventory
1265 * item leds associated with sensors. Stores the resulting data in the
1266 * inventoryItems vector.
1267 *
1268 * This data is later used to provide sensor property values in the JSON
1269 * response.
1270 *
1271 * Finds the inventory item led data asynchronously. Invokes callback when data
1272 * has been obtained.
1273 *
1274 * The callback must have the following signature:
1275 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001276 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001277 * @endcode
1278 *
1279 * This function is called recursively, obtaining data asynchronously from one
1280 * connection in each call. This ensures the callback is not invoked until the
1281 * last asynchronous function has completed.
1282 *
1283 * @param sensorsAsyncResp Pointer to object holding response data.
1284 * @param inventoryItems D-Bus inventory items associated with sensors.
1285 * @param ledConnections Connections that provide data for the inventory leds.
1286 * @param callback Callback to invoke when inventory data has been obtained.
1287 * @param ledConnectionsIndex Current index in ledConnections. Only specified
1288 * in recursive calls to this function.
1289 */
1290template <typename Callback>
1291void getInventoryLedData(
1292 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1293 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001294 std::shared_ptr<std::map<std::string, std::string>> ledConnections,
Anthony Wilsond5005492019-07-31 16:34:17 -05001295 Callback&& callback, size_t ledConnectionsIndex = 0)
1296{
Ed Tanous62598e32023-07-17 17:06:25 -07001297 BMCWEB_LOG_DEBUG("getInventoryLedData enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001298
1299 // If no more connections left, call callback
1300 if (ledConnectionsIndex >= ledConnections->size())
1301 {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001302 callback();
Ed Tanous62598e32023-07-17 17:06:25 -07001303 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001304 return;
1305 }
1306
1307 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +00001308 auto it = ledConnections->begin();
1309 std::advance(it, ledConnectionsIndex);
Anthony Wilsond5005492019-07-31 16:34:17 -05001310 if (it != ledConnections->end())
1311 {
1312 const std::string& ledPath = (*it).first;
1313 const std::string& ledConnection = (*it).second;
1314 // Response handler for Get State property
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001315 auto respHandler =
1316 [sensorsAsyncResp, inventoryItems, ledConnections, ledPath,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001317 callback = std::forward<Callback>(callback), ledConnectionsIndex](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001318 const boost::system::error_code& ec, const std::string& state) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001319 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler enter");
1320 if (ec)
1321 {
1322 BMCWEB_LOG_ERROR(
1323 "getInventoryLedData respHandler DBus error {}", ec);
1324 messages::internalError(sensorsAsyncResp->asyncResp->res);
1325 return;
1326 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001327
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001328 BMCWEB_LOG_DEBUG("Led state: {}", state);
1329 // Find inventory item with this LED object path
1330 InventoryItem* inventoryItem =
1331 findInventoryItemForLed(*inventoryItems, ledPath);
1332 if (inventoryItem != nullptr)
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001333 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001334 // Store LED state in InventoryItem
1335 if (state.ends_with("On"))
1336 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001337 inventoryItem->ledState = sensor_utils::LedState::ON;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001338 }
1339 else if (state.ends_with("Blink"))
1340 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001341 inventoryItem->ledState = sensor_utils::LedState::BLINK;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001342 }
1343 else if (state.ends_with("Off"))
1344 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001345 inventoryItem->ledState = sensor_utils::LedState::OFF;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001346 }
1347 else
1348 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001349 inventoryItem->ledState =
1350 sensor_utils::LedState::UNKNOWN;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001351 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001352 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001353
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001354 // Recurse to get LED data from next connection
1355 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1356 ledConnections, std::move(callback),
1357 ledConnectionsIndex + 1);
Anthony Wilsond5005492019-07-31 16:34:17 -05001358
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001359 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler exit");
1360 };
Anthony Wilsond5005492019-07-31 16:34:17 -05001361
1362 // Get the State property for the current LED
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001363 sdbusplus::asio::getProperty<std::string>(
1364 *crow::connections::systemBus, ledConnection, ledPath,
1365 "xyz.openbmc_project.Led.Physical", "State",
1366 std::move(respHandler));
Anthony Wilsond5005492019-07-31 16:34:17 -05001367 }
1368
Ed Tanous62598e32023-07-17 17:06:25 -07001369 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001370}
1371
1372/**
1373 * @brief Gets LED data for LEDs associated with given inventory items.
1374 *
1375 * Gets the D-Bus connections (services) that provide LED data for the LEDs
1376 * associated with the specified inventory items. Then gets the LED data from
1377 * each connection and stores it in the inventory item.
1378 *
1379 * This data is later used to provide sensor property values in the JSON
1380 * response.
1381 *
1382 * Finds the LED data asynchronously. Invokes callback when information has
1383 * been obtained.
1384 *
1385 * The callback must have the following signature:
1386 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001387 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001388 * @endcode
1389 *
1390 * @param sensorsAsyncResp Pointer to object holding response data.
1391 * @param inventoryItems D-Bus inventory items associated with sensors.
1392 * @param callback Callback to invoke when inventory items have been obtained.
1393 */
1394template <typename Callback>
1395void getInventoryLeds(
1396 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1397 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1398 Callback&& callback)
1399{
Ed Tanous62598e32023-07-17 17:06:25 -07001400 BMCWEB_LOG_DEBUG("getInventoryLeds enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001401
1402 const std::string path = "/xyz/openbmc_project";
George Liue99073f2022-12-09 11:06:16 +08001403 constexpr std::array<std::string_view, 1> interfaces = {
Anthony Wilsond5005492019-07-31 16:34:17 -05001404 "xyz.openbmc_project.Led.Physical"};
1405
George Liue99073f2022-12-09 11:06:16 +08001406 // Make call to ObjectMapper to find all inventory items
1407 dbus::utility::getSubTree(
1408 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001409 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001410 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001411 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001412 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001413 // Response handler for parsing output from GetSubTree
1414 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler enter");
1415 if (ec)
Anthony Wilsond5005492019-07-31 16:34:17 -05001416 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001417 messages::internalError(sensorsAsyncResp->asyncResp->res);
1418 BMCWEB_LOG_ERROR("getInventoryLeds respHandler DBus error {}",
1419 ec);
1420 return;
Anthony Wilsond5005492019-07-31 16:34:17 -05001421 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001422
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001423 // Build map of LED object paths to connections
1424 std::shared_ptr<std::map<std::string, std::string>> ledConnections =
1425 std::make_shared<std::map<std::string, std::string>>();
1426
1427 // Loop through objects from GetSubTree
1428 for (const std::pair<std::string,
1429 std::vector<std::pair<
1430 std::string, std::vector<std::string>>>>&
1431 object : subtree)
1432 {
1433 // Check if object path is LED for one of the specified
1434 // inventory items
1435 const std::string& ledPath = object.first;
1436 if (findInventoryItemForLed(*inventoryItems, ledPath) !=
1437 nullptr)
1438 {
1439 // Add mapping from ledPath to connection
1440 const std::string& connection =
1441 object.second.begin()->first;
1442 (*ledConnections)[ledPath] = connection;
1443 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", ledPath,
1444 connection);
1445 }
1446 }
1447
1448 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1449 ledConnections, std::move(callback));
1450 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler exit");
1451 });
Ed Tanous62598e32023-07-17 17:06:25 -07001452 BMCWEB_LOG_DEBUG("getInventoryLeds exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001453}
1454
1455/**
Gunnar Mills42cbe532019-08-15 15:26:54 -05001456 * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent
1457 *
1458 * Uses the specified connections (services) (currently assumes just one) to
1459 * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in
1460 * the inventoryItems vector. Only stores data in Power Supply inventoryItems.
1461 *
1462 * This data is later used to provide sensor property values in the JSON
1463 * response.
1464 *
1465 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1466 * when data has been obtained.
1467 *
1468 * The callback must have the following signature:
1469 * @code
1470 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1471 * @endcode
1472 *
1473 * @param sensorsAsyncResp Pointer to object holding response data.
1474 * @param inventoryItems D-Bus inventory items associated with sensors.
1475 * @param psAttributesConnections Connections that provide data for the Power
1476 * Supply Attributes
1477 * @param callback Callback to invoke when data has been obtained.
1478 */
1479template <typename Callback>
1480void getPowerSupplyAttributesData(
Ed Tanousb5a76932020-09-29 16:16:58 -07001481 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001482 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001483 const std::map<std::string, std::string>& psAttributesConnections,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001484 Callback&& callback)
1485{
Ed Tanous62598e32023-07-17 17:06:25 -07001486 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001487
1488 if (psAttributesConnections.empty())
1489 {
Ed Tanous62598e32023-07-17 17:06:25 -07001490 BMCWEB_LOG_DEBUG("Can't find PowerSupplyAttributes, no connections!");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001491 callback(inventoryItems);
1492 return;
1493 }
1494
1495 // Assuming just one connection (service) for now
Nan Zhoufe04d492022-06-22 17:10:41 +00001496 auto it = psAttributesConnections.begin();
Gunnar Mills42cbe532019-08-15 15:26:54 -05001497
1498 const std::string& psAttributesPath = (*it).first;
1499 const std::string& psAttributesConnection = (*it).second;
1500
1501 // Response handler for Get DeratingFactor property
Patrick Williams5a39f772023-10-20 11:20:21 -05001502 auto respHandler = [sensorsAsyncResp, inventoryItems,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001503 callback = std::forward<Callback>(callback)](
Patrick Williams5a39f772023-10-20 11:20:21 -05001504 const boost::system::error_code& ec,
1505 const uint32_t value) {
Ed Tanous62598e32023-07-17 17:06:25 -07001506 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001507 if (ec)
1508 {
Ed Tanous62598e32023-07-17 17:06:25 -07001509 BMCWEB_LOG_ERROR(
1510 "getPowerSupplyAttributesData respHandler DBus error {}", ec);
zhanghch058d1b46d2021-04-01 11:18:24 +08001511 messages::internalError(sensorsAsyncResp->asyncResp->res);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001512 return;
1513 }
1514
Ed Tanous62598e32023-07-17 17:06:25 -07001515 BMCWEB_LOG_DEBUG("PS EfficiencyPercent value: {}", value);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001516 // Store value in Power Supply Inventory Items
1517 for (InventoryItem& inventoryItem : *inventoryItems)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001518 {
Ed Tanous55f79e62022-01-25 11:26:16 -08001519 if (inventoryItem.isPowerSupply)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001520 {
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001521 inventoryItem.powerSupplyEfficiencyPercent =
1522 static_cast<int>(value);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001523 }
1524 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001525
Ed Tanous62598e32023-07-17 17:06:25 -07001526 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001527 callback(inventoryItems);
1528 };
1529
1530 // Get the DeratingFactor property for the PowerSupplyAttributes
1531 // Currently only property on the interface/only one we care about
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001532 sdbusplus::asio::getProperty<uint32_t>(
1533 *crow::connections::systemBus, psAttributesConnection, psAttributesPath,
1534 "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
1535 std::move(respHandler));
Gunnar Mills42cbe532019-08-15 15:26:54 -05001536
Ed Tanous62598e32023-07-17 17:06:25 -07001537 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001538}
1539
1540/**
1541 * @brief Gets the Power Supply Attributes such as EfficiencyPercent
1542 *
1543 * Gets the D-Bus connection (service) that provides Power Supply Attributes
1544 * data. Then gets the Power Supply Attributes data from the connection
1545 * (currently just assumes 1 connection) and stores the data in the inventory
1546 * item.
1547 *
1548 * This data is later used to provide sensor property values in the JSON
1549 * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish.
1550 *
1551 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1552 * when information has been obtained.
1553 *
1554 * The callback must have the following signature:
1555 * @code
1556 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1557 * @endcode
1558 *
1559 * @param sensorsAsyncResp Pointer to object holding response data.
1560 * @param inventoryItems D-Bus inventory items associated with sensors.
1561 * @param callback Callback to invoke when data has been obtained.
1562 */
1563template <typename Callback>
1564void getPowerSupplyAttributes(
1565 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1566 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1567 Callback&& callback)
1568{
Ed Tanous62598e32023-07-17 17:06:25 -07001569 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001570
1571 // Only need the power supply attributes when the Power Schema
Janet Adkinsc9563602024-08-28 11:37:46 -05001572 if (sensorsAsyncResp->chassisSubNode != sensor_utils::powerNode)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001573 {
Ed Tanous62598e32023-07-17 17:06:25 -07001574 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit since not Power");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001575 callback(inventoryItems);
1576 return;
1577 }
1578
George Liue99073f2022-12-09 11:06:16 +08001579 constexpr std::array<std::string_view, 1> interfaces = {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001580 "xyz.openbmc_project.Control.PowerSupplyAttributes"};
1581
George Liue99073f2022-12-09 11:06:16 +08001582 // Make call to ObjectMapper to find the PowerSupplyAttributes service
1583 dbus::utility::getSubTree(
1584 "/xyz/openbmc_project", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001585 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001586 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001587 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001588 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001589 // Response handler for parsing output from GetSubTree
1590 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler enter");
1591 if (ec)
1592 {
1593 messages::internalError(sensorsAsyncResp->asyncResp->res);
1594 BMCWEB_LOG_ERROR(
1595 "getPowerSupplyAttributes respHandler DBus error {}", ec);
1596 return;
1597 }
1598 if (subtree.empty())
1599 {
1600 BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
1601 callback(inventoryItems);
1602 return;
1603 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001604
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001605 // Currently we only support 1 power supply attribute, use this for
1606 // all the power supplies. Build map of object path to connection.
1607 // Assume just 1 connection and 1 path for now.
1608 std::map<std::string, std::string> psAttributesConnections;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001609
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001610 if (subtree[0].first.empty() || subtree[0].second.empty())
1611 {
1612 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1613 callback(inventoryItems);
1614 return;
1615 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001616
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001617 const std::string& psAttributesPath = subtree[0].first;
1618 const std::string& connection = subtree[0].second.begin()->first;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001619
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001620 if (connection.empty())
1621 {
1622 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1623 callback(inventoryItems);
1624 return;
1625 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001626
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001627 psAttributesConnections[psAttributesPath] = connection;
1628 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", psAttributesPath,
1629 connection);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001630
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001631 getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems,
1632 psAttributesConnections,
1633 std::move(callback));
1634 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler exit");
1635 });
Ed Tanous62598e32023-07-17 17:06:25 -07001636 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001637}
1638
1639/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001640 * @brief Gets inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001641 *
1642 * Finds the inventory items that are associated with the specified sensors.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001643 * Then gets D-Bus data for the inventory items, such as presence and VPD.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001644 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001645 * This data is later used to provide sensor property values in the JSON
1646 * response.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001647 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001648 * Finds the inventory items asynchronously. Invokes callback when the
1649 * inventory items have been obtained.
1650 *
1651 * The callback must have the following signature:
1652 * @code
1653 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1654 * @endcode
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001655 *
1656 * @param sensorsAsyncResp Pointer to object holding response data.
1657 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001658 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001659 * @param callback Callback to invoke when inventory items have been obtained.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001660 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001661template <typename Callback>
Ed Tanousd0090732022-10-04 17:22:56 -07001662static void
1663 getInventoryItems(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1664 const std::shared_ptr<std::set<std::string>> sensorNames,
1665 Callback&& callback)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001666{
Ed Tanous62598e32023-07-17 17:06:25 -07001667 BMCWEB_LOG_DEBUG("getInventoryItems enter");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001668 auto getInventoryItemAssociationsCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -07001669 [sensorsAsyncResp, callback = std::forward<Callback>(callback)](
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001670 std::shared_ptr<std::vector<InventoryItem>> inventoryItems) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001671 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb enter");
1672 auto getInventoryItemsConnectionsCb =
1673 [sensorsAsyncResp, inventoryItems,
1674 callback = std::forward<const Callback>(callback)](
1675 std::shared_ptr<std::set<std::string>> invConnections) {
1676 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb enter");
1677 auto getInventoryItemsDataCb =
1678 [sensorsAsyncResp, inventoryItems,
1679 callback{std::move(callback)}]() {
1680 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001681
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001682 auto getInventoryLedsCb =
1683 [sensorsAsyncResp, inventoryItems,
1684 callback{std::move(callback)}]() {
1685 BMCWEB_LOG_DEBUG(
1686 "getInventoryLedsCb enter");
1687 // Find Power Supply Attributes and get the
1688 // data
1689 getPowerSupplyAttributes(
1690 sensorsAsyncResp, inventoryItems,
1691 std::move(callback));
1692 BMCWEB_LOG_DEBUG("getInventoryLedsCb exit");
1693 };
1694
1695 // Find led connections and get the data
1696 getInventoryLeds(sensorsAsyncResp, inventoryItems,
1697 std::move(getInventoryLedsCb));
1698 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb exit");
1699 };
1700
1701 // Get inventory item data from connections
1702 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1703 invConnections,
1704 std::move(getInventoryItemsDataCb));
1705 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001706 };
1707
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001708 // Get connections that provide inventory item data
1709 getInventoryItemsConnections(
1710 sensorsAsyncResp, inventoryItems,
1711 std::move(getInventoryItemsConnectionsCb));
1712 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001713 };
1714
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001715 // Get associations from sensors to inventory items
Ed Tanousd0090732022-10-04 17:22:56 -07001716 getInventoryItemAssociations(sensorsAsyncResp, sensorNames,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001717 std::move(getInventoryItemAssociationsCb));
Ed Tanous62598e32023-07-17 17:06:25 -07001718 BMCWEB_LOG_DEBUG("getInventoryItems exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001719}
1720
1721/**
1722 * @brief Returns JSON PowerSupply object for the specified inventory item.
1723 *
1724 * Searches for a JSON PowerSupply object that matches the specified inventory
1725 * item. If one is not found, a new PowerSupply object is added to the JSON
1726 * array.
1727 *
1728 * Multiple sensors are often associated with one power supply inventory item.
1729 * As a result, multiple sensor values are stored in one JSON PowerSupply
1730 * object.
1731 *
1732 * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1733 * @param inventoryItem Inventory item for the power supply.
1734 * @param chassisId Chassis that contains the power supply.
1735 * @return JSON PowerSupply object for the specified inventory item.
1736 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001737inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001738 const InventoryItem& inventoryItem,
1739 const std::string& chassisId)
1740{
Ed Tanous18f8f602023-07-18 10:07:23 -07001741 std::string nameS;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001742 nameS.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001743 std::ranges::replace_copy(inventoryItem.name, nameS.begin(), '_', ' ');
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001744 // Check if matching PowerSupply object already exists in JSON array
1745 for (nlohmann::json& powerSupply : powerSupplyArray)
1746 {
Ed Tanous18f8f602023-07-18 10:07:23 -07001747 nlohmann::json::iterator nameIt = powerSupply.find("Name");
1748 if (nameIt == powerSupply.end())
1749 {
1750 continue;
1751 }
1752 const std::string* name = nameIt->get_ptr<std::string*>();
1753 if (name == nullptr)
1754 {
1755 continue;
1756 }
1757 if (nameS == *name)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001758 {
1759 return powerSupply;
1760 }
1761 }
1762
1763 // Add new PowerSupply object to JSON array
1764 powerSupplyArray.push_back({});
1765 nlohmann::json& powerSupply = powerSupplyArray.back();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001766 boost::urls::url url =
1767 boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
Willy Tueddfc432022-09-26 16:46:38 +00001768 url.set_fragment(("/PowerSupplies"_json_pointer).to_string());
1769 powerSupply["@odata.id"] = std::move(url);
Ed Tanous18f8f602023-07-18 10:07:23 -07001770 std::string escaped;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001771 escaped.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001772 std::ranges::replace_copy(inventoryItem.name, escaped.begin(), '_', ' ');
1773 powerSupply["Name"] = std::move(escaped);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001774 powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1775 powerSupply["Model"] = inventoryItem.model;
1776 powerSupply["PartNumber"] = inventoryItem.partNumber;
1777 powerSupply["SerialNumber"] = inventoryItem.serialNumber;
Janet Adkinsc9563602024-08-28 11:37:46 -05001778 sensor_utils::setLedState(powerSupply, &inventoryItem);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001779
Gunnar Mills42cbe532019-08-15 15:26:54 -05001780 if (inventoryItem.powerSupplyEfficiencyPercent >= 0)
1781 {
1782 powerSupply["EfficiencyPercent"] =
1783 inventoryItem.powerSupplyEfficiencyPercent;
1784 }
1785
Janet Adkinsc9563602024-08-28 11:37:46 -05001786 powerSupply["Status"]["State"] =
1787 sensor_utils::getState(&inventoryItem, true);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001788 const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1789 powerSupply["Status"]["Health"] = health;
1790
1791 return powerSupply;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001792}
1793
1794/**
Shawn McCarneyde629b62019-03-08 10:42:51 -06001795 * @brief Gets the values of the specified sensors.
1796 *
1797 * Stores the results as JSON in the SensorsAsyncResp.
1798 *
1799 * Gets the sensor values asynchronously. Stores the results later when the
1800 * information has been obtained.
1801 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001802 * The sensorNames set contains all requested sensors for the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001803 *
1804 * To minimize the number of DBus calls, the DBus method
1805 * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1806 * values of all sensors provided by a connection (service).
1807 *
1808 * The connections set contains all the connections that provide sensor values.
1809 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001810 * The InventoryItem vector contains D-Bus inventory items associated with the
1811 * sensors. Inventory item data is needed for some Redfish sensor properties.
1812 *
Shawn McCarneyde629b62019-03-08 10:42:51 -06001813 * @param SensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001814 * @param sensorNames All requested sensors within the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001815 * @param connections Connections that provide sensor values.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001816 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001817 * @param inventoryItems Inventory items associated with the sensors.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001818 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001819inline void getSensorData(
Ed Tanous81ce6092020-12-17 16:54:55 +00001820 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001821 const std::shared_ptr<std::set<std::string>>& sensorNames,
1822 const std::set<std::string>& connections,
Ed Tanousb5a76932020-09-29 16:16:58 -07001823 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001824{
Ed Tanous62598e32023-07-17 17:06:25 -07001825 BMCWEB_LOG_DEBUG("getSensorData enter");
Shawn McCarneyde629b62019-03-08 10:42:51 -06001826 // Get managed objects from all services exposing sensors
1827 for (const std::string& connection : connections)
1828 {
George Liu5eb468d2023-06-20 17:03:24 +08001829 sdbusplus::message::object_path sensorPath(
1830 "/xyz/openbmc_project/sensors");
1831 dbus::utility::getManagedObjects(
1832 connection, sensorPath,
Ed Tanous002d39b2022-05-31 08:59:27 -07001833 [sensorsAsyncResp, sensorNames,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001834 inventoryItems](const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -07001835 const dbus::utility::ManagedObjectType& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001836 BMCWEB_LOG_DEBUG("getManagedObjectsCb enter");
1837 if (ec)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001838 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001839 BMCWEB_LOG_ERROR("getManagedObjectsCb DBUS error: {}", ec);
1840 messages::internalError(sensorsAsyncResp->asyncResp->res);
1841 return;
1842 }
1843 // Go through all objects and update response with sensor data
1844 for (const auto& objDictEntry : resp)
1845 {
1846 const std::string& objPath =
1847 static_cast<const std::string&>(objDictEntry.first);
1848 BMCWEB_LOG_DEBUG("getManagedObjectsCb parsing object {}",
Ed Tanous62598e32023-07-17 17:06:25 -07001849 objPath);
Shawn McCarneyde629b62019-03-08 10:42:51 -06001850
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001851 std::vector<std::string> split;
1852 // Reserve space for
1853 // /xyz/openbmc_project/sensors/<name>/<subname>
1854 split.reserve(6);
1855 // NOLINTNEXTLINE
1856 bmcweb::split(split, objPath, '/');
1857 if (split.size() < 6)
Nan Zhou928fefb2022-03-28 08:45:00 -07001858 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001859 BMCWEB_LOG_ERROR("Got path that isn't long enough {}",
1860 objPath);
1861 continue;
Nan Zhou928fefb2022-03-28 08:45:00 -07001862 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001863 // These indexes aren't intuitive, as split puts an empty
1864 // string at the beginning
1865 const std::string& sensorType = split[4];
1866 const std::string& sensorName = split[5];
1867 BMCWEB_LOG_DEBUG("sensorName {} sensorType {}", sensorName,
1868 sensorType);
1869 if (sensorNames->find(objPath) == sensorNames->end())
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001870 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001871 BMCWEB_LOG_DEBUG("{} not in sensor list ", sensorName);
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001872 continue;
1873 }
1874
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001875 // Find inventory item (if any) associated with sensor
1876 InventoryItem* inventoryItem =
1877 findInventoryItemForSensor(inventoryItems, objPath);
1878
1879 const std::string& sensorSchema =
1880 sensorsAsyncResp->chassisSubNode;
1881
1882 nlohmann::json* sensorJson = nullptr;
1883
Janet Adkinsc9563602024-08-28 11:37:46 -05001884 if (sensorSchema == sensor_utils::sensorsNode &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001885 !sensorsAsyncResp->efficientExpand)
Nan Zhou928fefb2022-03-28 08:45:00 -07001886 {
Janet Adkins1516c212024-08-14 13:22:41 -05001887 std::string sensorId =
1888 redfish::sensor_utils::getSensorId(sensorName,
1889 sensorType);
Ed Tanous677bb752022-09-15 10:52:19 -07001890
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001891 sensorsAsyncResp->asyncResp->res
1892 .jsonValue["@odata.id"] = boost::urls::format(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001893 "/redfish/v1/Chassis/{}/{}/{}",
Ed Tanous677bb752022-09-15 10:52:19 -07001894 sensorsAsyncResp->chassisId,
1895 sensorsAsyncResp->chassisSubNode, sensorId);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001896 sensorJson =
1897 &(sensorsAsyncResp->asyncResp->res.jsonValue);
Nan Zhou928fefb2022-03-28 08:45:00 -07001898 }
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001899 else
1900 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001901 std::string fieldName;
1902 if (sensorsAsyncResp->efficientExpand)
1903 {
1904 fieldName = "Members";
1905 }
1906 else if (sensorType == "temperature")
1907 {
1908 fieldName = "Temperatures";
1909 }
1910 else if (sensorType == "fan" ||
1911 sensorType == "fan_tach" ||
1912 sensorType == "fan_pwm")
1913 {
1914 fieldName = "Fans";
1915 }
1916 else if (sensorType == "voltage")
1917 {
1918 fieldName = "Voltages";
1919 }
1920 else if (sensorType == "power")
1921 {
1922 if (sensorName == "total_power")
1923 {
1924 fieldName = "PowerControl";
1925 }
1926 else if ((inventoryItem != nullptr) &&
1927 (inventoryItem->isPowerSupply))
1928 {
1929 fieldName = "PowerSupplies";
1930 }
1931 else
1932 {
1933 // Other power sensors are in SensorCollection
1934 continue;
1935 }
1936 }
1937 else
1938 {
1939 BMCWEB_LOG_ERROR(
1940 "Unsure how to handle sensorType {}",
1941 sensorType);
1942 continue;
1943 }
1944
1945 nlohmann::json& tempArray =
1946 sensorsAsyncResp->asyncResp->res
1947 .jsonValue[fieldName];
1948 if (fieldName == "PowerControl")
1949 {
1950 if (tempArray.empty())
1951 {
1952 // Put multiple "sensors" into a single
1953 // PowerControl. Follows MemberId naming and
1954 // naming in power.hpp.
1955 nlohmann::json::object_t power;
1956 boost::urls::url url = boost::urls::format(
1957 "/redfish/v1/Chassis/{}/{}",
1958 sensorsAsyncResp->chassisId,
1959 sensorsAsyncResp->chassisSubNode);
1960 url.set_fragment(
1961 (""_json_pointer / fieldName / "0")
1962 .to_string());
1963 power["@odata.id"] = std::move(url);
1964 tempArray.emplace_back(std::move(power));
1965 }
1966 sensorJson = &(tempArray.back());
1967 }
1968 else if (fieldName == "PowerSupplies")
1969 {
1970 if (inventoryItem != nullptr)
1971 {
1972 sensorJson = &(getPowerSupply(
1973 tempArray, *inventoryItem,
1974 sensorsAsyncResp->chassisId));
1975 }
1976 }
1977 else if (fieldName == "Members")
1978 {
Janet Adkins1516c212024-08-14 13:22:41 -05001979 std::string sensorId =
1980 redfish::sensor_utils::getSensorId(sensorName,
1981 sensorType);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001982
1983 nlohmann::json::object_t member;
1984 member["@odata.id"] = boost::urls::format(
1985 "/redfish/v1/Chassis/{}/{}/{}",
1986 sensorsAsyncResp->chassisId,
1987 sensorsAsyncResp->chassisSubNode, sensorId);
1988 tempArray.emplace_back(std::move(member));
1989 sensorJson = &(tempArray.back());
1990 }
1991 else
1992 {
1993 nlohmann::json::object_t member;
1994 boost::urls::url url = boost::urls::format(
1995 "/redfish/v1/Chassis/{}/{}",
1996 sensorsAsyncResp->chassisId,
1997 sensorsAsyncResp->chassisSubNode);
1998 url.set_fragment(
1999 (""_json_pointer / fieldName).to_string());
2000 member["@odata.id"] = std::move(url);
2001 tempArray.emplace_back(std::move(member));
2002 sensorJson = &(tempArray.back());
2003 }
2004 }
2005
2006 if (sensorJson != nullptr)
2007 {
2008 objectInterfacesToJson(sensorName, sensorType,
2009 sensorsAsyncResp->chassisSubNode,
2010 objDictEntry.second, *sensorJson,
2011 inventoryItem);
2012
2013 std::string path = "/xyz/openbmc_project/sensors/";
2014 path += sensorType;
2015 path += "/";
2016 path += sensorName;
2017 sensorsAsyncResp->addMetadata(*sensorJson, path);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002018 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002019 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002020 if (sensorsAsyncResp.use_count() == 1)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002021 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002022 sortJSONResponse(sensorsAsyncResp);
2023 if (sensorsAsyncResp->chassisSubNode ==
Janet Adkinsc9563602024-08-28 11:37:46 -05002024 sensor_utils::sensorsNode &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002025 sensorsAsyncResp->efficientExpand)
2026 {
2027 sensorsAsyncResp->asyncResp->res
2028 .jsonValue["Members@odata.count"] =
2029 sensorsAsyncResp->asyncResp->res
2030 .jsonValue["Members"]
2031 .size();
2032 }
2033 else if (sensorsAsyncResp->chassisSubNode ==
Janet Adkinsc9563602024-08-28 11:37:46 -05002034 sensor_utils::thermalNode)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002035 {
2036 populateFanRedundancy(sensorsAsyncResp);
2037 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002038 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002039 BMCWEB_LOG_DEBUG("getManagedObjectsCb exit");
2040 });
Ed Tanous23a21a12020-07-25 04:45:05 +00002041 }
Ed Tanous62598e32023-07-17 17:06:25 -07002042 BMCWEB_LOG_DEBUG("getSensorData exit");
Shawn McCarneyde629b62019-03-08 10:42:51 -06002043}
2044
Nan Zhoufe04d492022-06-22 17:10:41 +00002045inline void
2046 processSensorList(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
2047 const std::shared_ptr<std::set<std::string>>& sensorNames)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002048{
Nan Zhoufe04d492022-06-22 17:10:41 +00002049 auto getConnectionCb = [sensorsAsyncResp, sensorNames](
2050 const std::set<std::string>& connections) {
Ed Tanous62598e32023-07-17 17:06:25 -07002051 BMCWEB_LOG_DEBUG("getConnectionCb enter");
Ed Tanousd0090732022-10-04 17:22:56 -07002052 auto getInventoryItemsCb =
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002053 [sensorsAsyncResp, sensorNames, connections](
2054 const std::shared_ptr<std::vector<InventoryItem>>&
2055 inventoryItems) {
2056 BMCWEB_LOG_DEBUG("getInventoryItemsCb enter");
2057 // Get sensor data and store results in JSON
2058 getSensorData(sensorsAsyncResp, sensorNames, connections,
2059 inventoryItems);
2060 BMCWEB_LOG_DEBUG("getInventoryItemsCb exit");
2061 };
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002062
Ed Tanousd0090732022-10-04 17:22:56 -07002063 // Get inventory items associated with sensors
2064 getInventoryItems(sensorsAsyncResp, sensorNames,
2065 std::move(getInventoryItemsCb));
2066
Ed Tanous62598e32023-07-17 17:06:25 -07002067 BMCWEB_LOG_DEBUG("getConnectionCb exit");
Ed Tanous002d39b2022-05-31 08:59:27 -07002068 };
2069
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002070 // Get set of connections that provide sensor values
Ed Tanous81ce6092020-12-17 16:54:55 +00002071 getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002072}
2073
Shawn McCarneyde629b62019-03-08 10:42:51 -06002074/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002075 * @brief Entry point for retrieving sensors data related to requested
2076 * chassis.
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02002077 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002078 */
Ed Tanousb5a76932020-09-29 16:16:58 -07002079inline void
Ed Tanous81ce6092020-12-17 16:54:55 +00002080 getChassisData(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002081{
Ed Tanous62598e32023-07-17 17:06:25 -07002082 BMCWEB_LOG_DEBUG("getChassisData enter");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002083 auto getChassisCb =
Ed Tanous81ce6092020-12-17 16:54:55 +00002084 [sensorsAsyncResp](
Nan Zhoufe04d492022-06-22 17:10:41 +00002085 const std::shared_ptr<std::set<std::string>>& sensorNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002086 BMCWEB_LOG_DEBUG("getChassisCb enter");
2087 processSensorList(sensorsAsyncResp, sensorNames);
2088 BMCWEB_LOG_DEBUG("getChassisCb exit");
2089 };
Nan Zhou928fefb2022-03-28 08:45:00 -07002090 // SensorCollection doesn't contain the Redundancy property
Janet Adkinsc9563602024-08-28 11:37:46 -05002091 if (sensorsAsyncResp->chassisSubNode != sensor_utils::sensorsNode)
Nan Zhou928fefb2022-03-28 08:45:00 -07002092 {
2093 sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
2094 nlohmann::json::array();
2095 }
Shawn McCarney26f03892019-05-03 13:20:24 -05002096 // Get set of sensors in chassis
Ed Tanous7f1cc262022-08-09 13:33:57 -07002097 getChassis(sensorsAsyncResp->asyncResp, sensorsAsyncResp->chassisId,
2098 sensorsAsyncResp->chassisSubNode, sensorsAsyncResp->types,
2099 std::move(getChassisCb));
Ed Tanous62598e32023-07-17 17:06:25 -07002100 BMCWEB_LOG_DEBUG("getChassisData exit");
Ed Tanous271584a2019-07-09 16:24:22 -07002101}
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002102
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302103/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002104 * @brief Find the requested sensorName in the list of all sensors supplied by
2105 * the chassis node
2106 *
2107 * @param sensorName The sensor name supplied in the PATCH request
2108 * @param sensorsList The list of sensors managed by the chassis node
2109 * @param sensorsModified The list of sensors that were found as a result of
2110 * repeated calls to this function
2111 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002112inline bool findSensorNameUsingSensorPath(
2113 std::string_view sensorName, const std::set<std::string>& sensorsList,
2114 std::set<std::string>& sensorsModified)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002115{
Nan Zhoufe04d492022-06-22 17:10:41 +00002116 for (const auto& chassisSensor : sensorsList)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002117 {
George Liu28aa8de2021-02-01 15:13:30 +08002118 sdbusplus::message::object_path path(chassisSensor);
Ed Tanousb00dcc22021-02-23 12:52:50 -08002119 std::string thisSensorName = path.filename();
George Liu28aa8de2021-02-01 15:13:30 +08002120 if (thisSensorName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002121 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002122 continue;
2123 }
2124 if (thisSensorName == sensorName)
2125 {
2126 sensorsModified.emplace(chassisSensor);
2127 return true;
2128 }
2129 }
2130 return false;
2131}
2132
2133/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302134 * @brief Entry point for overriding sensor values of given sensor
2135 *
zhanghch058d1b46d2021-04-01 11:18:24 +08002136 * @param sensorAsyncResp response object
Carol Wang4bb3dc32019-10-17 18:15:02 +08002137 * @param allCollections Collections extract from sensors' request patch info
jayaprakash Mutyala91e130a2020-03-04 22:26:38 +00002138 * @param chassisSubNode Chassis Node for which the query has to happen
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302139 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002140inline void setSensorsOverride(
Ed Tanousb5a76932020-09-29 16:16:58 -07002141 const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
Ed Tanous08850572024-03-06 15:09:17 -08002142 std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>&
jayaprakash Mutyala397fd612020-02-06 23:33:34 +00002143 allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302144{
Ed Tanous62598e32023-07-17 17:06:25 -07002145 BMCWEB_LOG_INFO("setSensorsOverride for subNode{}",
2146 sensorAsyncResp->chassisSubNode);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302147
Ed Tanousd02aad32024-02-13 14:43:34 -08002148 std::string_view propertyValueName;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302149 std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302150 std::string memberId;
Ed Tanous543f4402022-01-06 13:12:53 -08002151 double value = 0.0;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302152 for (auto& collectionItems : allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302153 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302154 if (collectionItems.first == "Temperatures")
2155 {
2156 propertyValueName = "ReadingCelsius";
2157 }
2158 else if (collectionItems.first == "Fans")
2159 {
2160 propertyValueName = "Reading";
2161 }
2162 else
2163 {
2164 propertyValueName = "ReadingVolts";
2165 }
2166 for (auto& item : collectionItems.second)
2167 {
Ed Tanous08850572024-03-06 15:09:17 -08002168 if (!json_util::readJsonObject(
2169 item, sensorAsyncResp->asyncResp->res, "MemberId", memberId,
2170 propertyValueName, value))
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302171 {
2172 return;
2173 }
2174 overrideMap.emplace(memberId,
2175 std::make_pair(value, collectionItems.first));
2176 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302177 }
Carol Wang4bb3dc32019-10-17 18:15:02 +08002178
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002179 auto getChassisSensorListCb = [sensorAsyncResp, overrideMap,
2180 propertyValueNameStr =
2181 std::string(propertyValueName)](
2182 const std::shared_ptr<
2183 std::set<std::string>>& sensorsList) {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002184 // Match sensor names in the PATCH request to those managed by the
2185 // chassis node
Nan Zhoufe04d492022-06-22 17:10:41 +00002186 const std::shared_ptr<std::set<std::string>> sensorNames =
2187 std::make_shared<std::set<std::string>>();
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302188 for (const auto& item : overrideMap)
2189 {
2190 const auto& sensor = item.first;
Ed Tanousc71d6122022-11-29 14:10:32 -08002191 std::pair<std::string, std::string> sensorNameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002192 redfish::sensor_utils::splitSensorNameAndType(sensor);
Ed Tanousc71d6122022-11-29 14:10:32 -08002193 if (!findSensorNameUsingSensorPath(sensorNameType.second,
2194 *sensorsList, *sensorNames))
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302195 {
Ed Tanous62598e32023-07-17 17:06:25 -07002196 BMCWEB_LOG_INFO("Unable to find memberId {}", item.first);
zhanghch058d1b46d2021-04-01 11:18:24 +08002197 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302198 item.second.second, item.first);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302199 return;
2200 }
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302201 }
2202 // Get the connection to which the memberId belongs
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002203 auto getObjectsWithConnectionCb = [sensorAsyncResp, overrideMap,
2204 propertyValueNameStr](
2205 const std::set<
2206 std::string>& /*connections*/,
2207 const std::set<std::pair<
2208 std::string, std::string>>&
2209 objectsWithConnection) {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002210 if (objectsWithConnection.size() != overrideMap.size())
2211 {
Ed Tanous62598e32023-07-17 17:06:25 -07002212 BMCWEB_LOG_INFO(
2213 "Unable to find all objects with proper connection {} requested {}",
2214 objectsWithConnection.size(), overrideMap.size());
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002215 messages::resourceNotFound(
2216 sensorAsyncResp->asyncResp->res,
Janet Adkinsc9563602024-08-28 11:37:46 -05002217 sensorAsyncResp->chassisSubNode == sensor_utils::thermalNode
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002218 ? "Temperatures"
2219 : "Voltages",
2220 "Count");
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002221 return;
2222 }
2223 for (const auto& item : objectsWithConnection)
2224 {
2225 sdbusplus::message::object_path path(item.first);
2226 std::string sensorName = path.filename();
2227 if (sensorName.empty())
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302228 {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002229 messages::internalError(sensorAsyncResp->asyncResp->res);
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302230 return;
2231 }
Janet Adkins1516c212024-08-14 13:22:41 -05002232 std::string id = redfish::sensor_utils::getSensorId(
2233 sensorName, path.parent_path().filename());
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302234
Ban Feng3f5eb752023-06-29 09:19:20 +08002235 const auto& iterator = overrideMap.find(id);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002236 if (iterator == overrideMap.end())
2237 {
Ed Tanous62598e32023-07-17 17:06:25 -07002238 BMCWEB_LOG_INFO("Unable to find sensor object{}",
2239 item.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002240 messages::internalError(sensorAsyncResp->asyncResp->res);
2241 return;
2242 }
Ginu Georgee93abac2024-06-14 17:35:27 +05302243 setDbusProperty(sensorAsyncResp->asyncResp,
2244 propertyValueNameStr, item.second, item.first,
2245 "xyz.openbmc_project.Sensor.Value", "Value",
Ed Tanousd02aad32024-02-13 14:43:34 -08002246 iterator->second.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002247 }
2248 };
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302249 // Get object with connection for the given sensor name
2250 getObjectsWithConnection(sensorAsyncResp, sensorNames,
2251 std::move(getObjectsWithConnectionCb));
2252 };
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302253 // get full sensor list for the given chassisId and cross verify the sensor.
Ed Tanous7f1cc262022-08-09 13:33:57 -07002254 getChassis(sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId,
2255 sensorAsyncResp->chassisSubNode, sensorAsyncResp->types,
2256 std::move(getChassisSensorListCb));
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302257}
2258
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002259/**
2260 * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus
2261 * path of the sensor.
2262 *
2263 * Function builds valid Redfish response for sensor query of given chassis and
2264 * node. It then builds metadata about Redfish<->D-Bus correlations and provides
2265 * it to caller in a callback.
2266 *
2267 * @param chassis Chassis for which retrieval should be performed
Janet Adkinsc9563602024-08-28 11:37:46 -05002268 * @param node Node (group) of sensors. See sensor_utils::node for supported
2269 * values
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002270 * @param mapComplete Callback to be called with retrieval result
2271 */
Ed Tanous931edc72023-11-01 12:09:07 -07002272template <typename Callback>
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002273inline void retrieveUriToDbusMap(
2274 const std::string& chassis, const std::string& node, Callback&& mapComplete)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002275{
Ed Tanous02da7c52022-02-27 00:09:02 -08002276 decltype(sensors::paths)::const_iterator pathIt =
2277 std::find_if(sensors::paths.cbegin(), sensors::paths.cend(),
2278 [&node](auto&& val) { return val.first == node; });
2279 if (pathIt == sensors::paths.cend())
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002280 {
Ed Tanous62598e32023-07-17 17:06:25 -07002281 BMCWEB_LOG_ERROR("Wrong node provided : {}", node);
Ed Tanous6804b5c2023-10-31 14:50:03 -07002282 std::map<std::string, std::string> noop;
2283 mapComplete(boost::beast::http::status::bad_request, noop);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002284 return;
2285 }
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002286
Nan Zhou72374eb2022-01-27 17:06:51 -08002287 auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002288 auto callback =
2289 [asyncResp, mapCompleteCb = std::forward<Callback>(mapComplete)](
2290 const boost::beast::http::status status,
2291 const std::map<std::string, std::string>& uriToDbus) {
2292 mapCompleteCb(status, uriToDbus);
2293 };
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002294
2295 auto resp = std::make_shared<SensorsAsyncResp>(
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002296 asyncResp, chassis, pathIt->second, node, std::move(callback));
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002297 getChassisData(resp);
2298}
2299
Nan Zhoubacb2162022-04-06 11:28:32 -07002300namespace sensors
2301{
Nan Zhou928fefb2022-03-28 08:45:00 -07002302
Nan Zhoubacb2162022-04-06 11:28:32 -07002303inline void getChassisCallback(
Ed Tanousc1d019a2022-08-06 09:36:06 -07002304 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2305 std::string_view chassisId, std::string_view chassisSubNode,
Nan Zhoufe04d492022-06-22 17:10:41 +00002306 const std::shared_ptr<std::set<std::string>>& sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002307{
Ed Tanous62598e32023-07-17 17:06:25 -07002308 BMCWEB_LOG_DEBUG("getChassisCallback enter ");
Nan Zhoubacb2162022-04-06 11:28:32 -07002309
Ed Tanousc1d019a2022-08-06 09:36:06 -07002310 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
2311 for (const std::string& sensor : *sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002312 {
Ed Tanous62598e32023-07-17 17:06:25 -07002313 BMCWEB_LOG_DEBUG("Adding sensor: {}", sensor);
Nan Zhoubacb2162022-04-06 11:28:32 -07002314
2315 sdbusplus::message::object_path path(sensor);
2316 std::string sensorName = path.filename();
2317 if (sensorName.empty())
2318 {
Ed Tanous62598e32023-07-17 17:06:25 -07002319 BMCWEB_LOG_ERROR("Invalid sensor path: {}", sensor);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002320 messages::internalError(asyncResp->res);
Nan Zhoubacb2162022-04-06 11:28:32 -07002321 return;
2322 }
Ed Tanousc1d019a2022-08-06 09:36:06 -07002323 std::string type = path.parent_path().filename();
Janet Adkins1516c212024-08-14 13:22:41 -05002324 std::string id = redfish::sensor_utils::getSensorId(sensorName, type);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002325
Ed Tanous14766872022-03-15 10:44:42 -07002326 nlohmann::json::object_t member;
Ed Tanousef4c65b2023-04-24 15:28:50 -07002327 member["@odata.id"] = boost::urls::format(
2328 "/redfish/v1/Chassis/{}/{}/{}", chassisId, chassisSubNode, id);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002329
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002330 entriesArray.emplace_back(std::move(member));
Nan Zhoubacb2162022-04-06 11:28:32 -07002331 }
2332
Ed Tanousc1d019a2022-08-06 09:36:06 -07002333 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Ed Tanous62598e32023-07-17 17:06:25 -07002334 BMCWEB_LOG_DEBUG("getChassisCallback exit");
Nan Zhoubacb2162022-04-06 11:28:32 -07002335}
Nan Zhoue6bd8462022-06-01 04:35:35 +00002336
Ed Tanousac106bf2023-06-07 09:24:59 -07002337inline void handleSensorCollectionGet(
2338 App& app, const crow::Request& req,
2339 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2340 const std::string& chassisId)
Nan Zhoude167a62022-06-01 04:47:45 +00002341{
2342 query_param::QueryCapabilities capabilities = {
2343 .canDelegateExpandLevel = 1,
2344 };
2345 query_param::Query delegatedQuery;
Ed Tanousac106bf2023-06-07 09:24:59 -07002346 if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
Nan Zhoude167a62022-06-01 04:47:45 +00002347 delegatedQuery, capabilities))
2348 {
2349 return;
2350 }
2351
2352 if (delegatedQuery.expandType != query_param::ExpandType::None)
2353 {
2354 // we perform efficient expand.
Ed Tanousac106bf2023-06-07 09:24:59 -07002355 auto sensorsAsyncResp = std::make_shared<SensorsAsyncResp>(
2356 asyncResp, chassisId, sensors::dbus::sensorPaths,
Janet Adkinsc9563602024-08-28 11:37:46 -05002357 sensor_utils::sensorsNode,
Nan Zhoude167a62022-06-01 04:47:45 +00002358 /*efficientExpand=*/true);
Ed Tanousac106bf2023-06-07 09:24:59 -07002359 getChassisData(sensorsAsyncResp);
Nan Zhoude167a62022-06-01 04:47:45 +00002360
Ed Tanous62598e32023-07-17 17:06:25 -07002361 BMCWEB_LOG_DEBUG(
2362 "SensorCollection doGet exit via efficient expand handler");
Nan Zhoude167a62022-06-01 04:47:45 +00002363 return;
Ed Tanous0bad3202022-06-02 13:53:59 -07002364 }
Nan Zhoude167a62022-06-01 04:47:45 +00002365
Nan Zhoude167a62022-06-01 04:47:45 +00002366 // We get all sensors as hyperlinkes in the chassis (this
2367 // implies we reply on the default query parameters handler)
Janet Adkinsc9563602024-08-28 11:37:46 -05002368 getChassis(asyncResp, chassisId, sensor_utils::sensorsNode,
2369 dbus::sensorPaths,
Ed Tanousac106bf2023-06-07 09:24:59 -07002370 std::bind_front(sensors::getChassisCallback, asyncResp,
Janet Adkinsc9563602024-08-28 11:37:46 -05002371 chassisId, sensor_utils::sensorsNode));
Ed Tanousc1d019a2022-08-06 09:36:06 -07002372}
Ed Tanous7f1cc262022-08-09 13:33:57 -07002373
Ed Tanousc1d019a2022-08-06 09:36:06 -07002374inline void
2375 getSensorFromDbus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2376 const std::string& sensorPath,
2377 const ::dbus::utility::MapperGetObject& mapperResponse)
2378{
2379 if (mapperResponse.size() != 1)
2380 {
2381 messages::internalError(asyncResp->res);
2382 return;
2383 }
2384 const auto& valueIface = *mapperResponse.begin();
2385 const std::string& connectionName = valueIface.first;
Ed Tanous62598e32023-07-17 17:06:25 -07002386 BMCWEB_LOG_DEBUG("Looking up {}", connectionName);
2387 BMCWEB_LOG_DEBUG("Path {}", sensorPath);
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +02002388
2389 sdbusplus::asio::getAllProperties(
2390 *crow::connections::systemBus, connectionName, sensorPath, "",
Ed Tanousc1d019a2022-08-06 09:36:06 -07002391 [asyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002392 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002393 const ::dbus::utility::DBusPropertiesMap& valuesDict) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002394 if (ec)
2395 {
2396 messages::internalError(asyncResp->res);
2397 return;
2398 }
2399 sdbusplus::message::object_path path(sensorPath);
2400 std::string name = path.filename();
2401 path = path.parent_path();
2402 std::string type = path.filename();
Janet Adkinsc9563602024-08-28 11:37:46 -05002403 sensor_utils::objectPropertiesToJson(
2404 name, type, sensor_utils::sensorsNode, valuesDict,
2405 asyncResp->res.jsonValue, nullptr);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002406 });
Nan Zhoude167a62022-06-01 04:47:45 +00002407}
2408
Nan Zhoue6bd8462022-06-01 04:35:35 +00002409inline void handleSensorGet(App& app, const crow::Request& req,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002410 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous677bb752022-09-15 10:52:19 -07002411 const std::string& chassisId,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002412 const std::string& sensorId)
Nan Zhoue6bd8462022-06-01 04:35:35 +00002413{
Ed Tanousc1d019a2022-08-06 09:36:06 -07002414 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Nan Zhoue6bd8462022-06-01 04:35:35 +00002415 {
2416 return;
2417 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002418 std::pair<std::string, std::string> nameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002419 redfish::sensor_utils::splitSensorNameAndType(sensorId);
Ed Tanousc71d6122022-11-29 14:10:32 -08002420 if (nameType.first.empty() || nameType.second.empty())
Ed Tanousc1d019a2022-08-06 09:36:06 -07002421 {
2422 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2423 return;
2424 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002425
Ed Tanousef4c65b2023-04-24 15:28:50 -07002426 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2427 "/redfish/v1/Chassis/{}/Sensors/{}", chassisId, sensorId);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002428
Ed Tanous62598e32023-07-17 17:06:25 -07002429 BMCWEB_LOG_DEBUG("Sensor doGet enter");
Nan Zhoue6bd8462022-06-01 04:35:35 +00002430
George Liu2b731192023-01-11 16:27:13 +08002431 constexpr std::array<std::string_view, 1> interfaces = {
Nan Zhoue6bd8462022-06-01 04:35:35 +00002432 "xyz.openbmc_project.Sensor.Value"};
Ed Tanousc71d6122022-11-29 14:10:32 -08002433 std::string sensorPath = "/xyz/openbmc_project/sensors/" + nameType.first +
2434 '/' + nameType.second;
Nan Zhoue6bd8462022-06-01 04:35:35 +00002435 // Get a list of all of the sensors that implement Sensor.Value
2436 // and get the path and service name associated with the sensor
George Liu2b731192023-01-11 16:27:13 +08002437 ::dbus::utility::getDbusObject(
2438 sensorPath, interfaces,
Myung Baeaec0ec32023-05-31 15:10:01 -05002439 [asyncResp, sensorId,
George Liu2b731192023-01-11 16:27:13 +08002440 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002441 const ::dbus::utility::MapperGetObject& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002442 BMCWEB_LOG_DEBUG("respHandler1 enter");
2443 if (ec == boost::system::errc::io_error)
2444 {
2445 BMCWEB_LOG_WARNING("Sensor not found from getSensorPaths");
2446 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2447 return;
2448 }
2449 if (ec)
2450 {
2451 messages::internalError(asyncResp->res);
2452 BMCWEB_LOG_ERROR(
2453 "Sensor getSensorPaths resp_handler: Dbus error {}", ec);
2454 return;
2455 }
2456 getSensorFromDbus(asyncResp, sensorPath, subtree);
2457 BMCWEB_LOG_DEBUG("respHandler1 exit");
2458 });
Nan Zhoue6bd8462022-06-01 04:35:35 +00002459}
2460
Nan Zhoubacb2162022-04-06 11:28:32 -07002461} // namespace sensors
2462
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002463inline void requestRoutesSensorCollection(App& app)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002464{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002465 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
Ed Tanoused398212021-06-09 17:05:54 -07002466 .privileges(redfish::privileges::getSensorCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002467 .methods(boost::beast::http::verb::get)(
Nan Zhoude167a62022-06-01 04:47:45 +00002468 std::bind_front(sensors::handleSensorCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002469}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002470
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002471inline void requestRoutesSensor(App& app)
2472{
2473 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002474 .privileges(redfish::privileges::getSensor)
Ed Tanous002d39b2022-05-31 08:59:27 -07002475 .methods(boost::beast::http::verb::get)(
Nan Zhoue6bd8462022-06-01 04:35:35 +00002476 std::bind_front(sensors::handleSensorGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002477}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002478
Ed Tanous1abe55e2018-09-05 08:30:59 -07002479} // namespace redfish