blob: fe5d1ee3768cd5f6a4433a3f20f7f3e6aac7c18a [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
3// SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01004#pragma once
5
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08006#include "app.hpp"
7#include "dbus_singleton.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +08008#include "dbus_utility.hpp"
Ed Tanous539d8c62024-06-19 14:38:27 -07009#include "generated/enums/redundancy.hpp"
Matt Simmeringaaf08ac2023-10-04 08:41:01 -070010#include "generated/enums/resource.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080011#include "query.hpp"
12#include "registries/privilege_registry.hpp"
Ed Tanous50ebd4a2023-01-19 19:03:17 -080013#include "str_utility.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080014#include "utils/dbus_utils.hpp"
15#include "utils/json_utils.hpp"
16#include "utils/query_param.hpp"
Janet Adkins1516c212024-08-14 13:22:41 -050017#include "utils/sensor_utils.hpp"
Ed Tanous0ec8b832022-03-14 14:56:47 -070018
George Liue99073f2022-12-09 11:06:16 +080019#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070020#include <boost/url/format.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070021#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +020022#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050023
George Liu7a1dbc42022-12-07 16:03:22 +080024#include <array>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050025#include <cmath>
Nan Zhoufe04d492022-06-22 17:10:41 +000026#include <iterator>
Ed Tanous283860f2022-08-29 14:08:50 -070027#include <limits>
Nan Zhoufe04d492022-06-22 17:10:41 +000028#include <map>
Ed Tanous3544d2a2023-08-06 18:12:20 -070029#include <ranges>
Nan Zhoufe04d492022-06-22 17:10:41 +000030#include <set>
Ed Tanous18f8f602023-07-18 10:07:23 -070031#include <string>
George Liu7a1dbc42022-12-07 16:03:22 +080032#include <string_view>
Ed Tanousb5a76932020-09-29 16:16:58 -070033#include <utility>
Ed Tanousabf2add2019-01-22 16:40:12 -080034#include <variant>
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010035
Ed Tanous1abe55e2018-09-05 08:30:59 -070036namespace redfish
37{
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010038
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020039namespace sensors
40{
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020041
Ed Tanous02da7c52022-02-27 00:09:02 -080042// clang-format off
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020043namespace dbus
44{
Ed Tanouscf9e4172022-12-21 09:30:16 -080045constexpr auto powerPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080046 "/xyz/openbmc_project/sensors/voltage",
47 "/xyz/openbmc_project/sensors/power"
48});
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000049
Ed Tanous25b54db2024-04-17 15:40:31 -070050constexpr auto getSensorPaths(){
51 if constexpr(BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM){
52 return std::to_array<std::string_view>({
53 "/xyz/openbmc_project/sensors/power",
54 "/xyz/openbmc_project/sensors/current",
55 "/xyz/openbmc_project/sensors/airflow",
56 "/xyz/openbmc_project/sensors/humidity",
57 "/xyz/openbmc_project/sensors/voltage",
58 "/xyz/openbmc_project/sensors/fan_tach",
59 "/xyz/openbmc_project/sensors/temperature",
60 "/xyz/openbmc_project/sensors/fan_pwm",
61 "/xyz/openbmc_project/sensors/altitude",
62 "/xyz/openbmc_project/sensors/energy",
63 "/xyz/openbmc_project/sensors/utilization"});
64 } else {
65 return std::to_array<std::string_view>({"/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/utilization"});
70}
71}
72
73constexpr auto sensorPaths = getSensorPaths();
Ed Tanous02da7c52022-02-27 00:09:02 -080074
Ed Tanouscf9e4172022-12-21 09:30:16 -080075constexpr auto thermalPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080076 "/xyz/openbmc_project/sensors/fan_tach",
77 "/xyz/openbmc_project/sensors/temperature",
78 "/xyz/openbmc_project/sensors/fan_pwm"
79});
80
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000081} // namespace dbus
Ed Tanous02da7c52022-02-27 00:09:02 -080082// clang-format on
83
Janet Adkins0c728b42024-08-29 11:09:10 -050084constexpr std::string_view powerNodeStr = sensor_utils::chassisSubNodeToString(
85 sensor_utils::ChassisSubNode::powerNode);
86constexpr std::string_view sensorsNodeStr =
87 sensor_utils::chassisSubNodeToString(
88 sensor_utils::ChassisSubNode::sensorsNode);
89constexpr std::string_view thermalNodeStr =
90 sensor_utils::chassisSubNodeToString(
91 sensor_utils::ChassisSubNode::thermalNode);
92
Ed Tanouscf9e4172022-12-21 09:30:16 -080093using sensorPair =
94 std::pair<std::string_view, std::span<const std::string_view>>;
Ed Tanous02da7c52022-02-27 00:09:02 -080095static constexpr std::array<sensorPair, 3> paths = {
Janet Adkins0c728b42024-08-29 11:09:10 -050096 {{sensors::powerNodeStr, dbus::powerPaths},
97 {sensors::sensorsNodeStr, dbus::sensorPaths},
98 {sensors::thermalNodeStr, dbus::thermalPaths}}};
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000099
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200100} // namespace sensors
101
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100102/**
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200103 * SensorsAsyncResp
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100104 * Gathers data needed for response processing after async calls are done
105 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700106class SensorsAsyncResp
107{
108 public:
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200109 using DataCompleteCb = std::function<void(
110 const boost::beast::http::status status,
Nan Zhoufe04d492022-06-22 17:10:41 +0000111 const std::map<std::string, std::string>& uriToDbus)>;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200112
113 struct SensorData
114 {
Ed Tanousf836c1d2024-09-06 16:05:11 -0700115 std::string name;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200116 std::string uri;
Ed Tanousf836c1d2024-09-06 16:05:11 -0700117 std::string dbusPath;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200118 };
119
Ed Tanous8a592812022-06-04 09:06:59 -0700120 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800121 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800122 std::span<const std::string_view> typesIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800123 std::string_view subNode) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400124 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
125 chassisSubNode(subNode), efficientExpand(false)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500126 {}
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200127
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200128 // Store extra data about sensor mapping and return it in callback
Ed Tanous8a592812022-06-04 09:06:59 -0700129 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800130 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800131 std::span<const std::string_view> typesIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800132 std::string_view subNode,
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200133 DataCompleteCb&& creationComplete) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400134 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
135 chassisSubNode(subNode), efficientExpand(false),
136 metadata{std::vector<SensorData>()},
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200137 dataComplete{std::move(creationComplete)}
138 {}
139
Nan Zhou928fefb2022-03-28 08:45:00 -0700140 // sensor collections expand
Ed Tanous8a592812022-06-04 09:06:59 -0700141 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
Nan Zhou928fefb2022-03-28 08:45:00 -0700142 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800143 std::span<const std::string_view> typesIn,
Ed Tanous8a592812022-06-04 09:06:59 -0700144 const std::string_view& subNode, bool efficientExpandIn) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400145 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
146 chassisSubNode(subNode), efficientExpand(efficientExpandIn)
Nan Zhou928fefb2022-03-28 08:45:00 -0700147 {}
148
Ed Tanous1abe55e2018-09-05 08:30:59 -0700149 ~SensorsAsyncResp()
150 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800151 if (asyncResp->res.result() ==
152 boost::beast::http::status::internal_server_error)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700153 {
154 // Reset the json object to clear out any data that made it in
155 // before the error happened todo(ed) handle error condition with
156 // proper code
zhanghch058d1b46d2021-04-01 11:18:24 +0800157 asyncResp->res.jsonValue = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700158 }
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200159
160 if (dataComplete && metadata)
161 {
Nan Zhoufe04d492022-06-22 17:10:41 +0000162 std::map<std::string, std::string> map;
zhanghch058d1b46d2021-04-01 11:18:24 +0800163 if (asyncResp->res.result() == boost::beast::http::status::ok)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200164 {
165 for (auto& sensor : *metadata)
166 {
Ed Tanousc1d019a2022-08-06 09:36:06 -0700167 map.emplace(sensor.uri, sensor.dbusPath);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200168 }
169 }
zhanghch058d1b46d2021-04-01 11:18:24 +0800170 dataComplete(asyncResp->res.result(), map);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200171 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700172 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100173
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800174 SensorsAsyncResp(const SensorsAsyncResp&) = delete;
175 SensorsAsyncResp(SensorsAsyncResp&&) = delete;
176 SensorsAsyncResp& operator=(const SensorsAsyncResp&) = delete;
177 SensorsAsyncResp& operator=(SensorsAsyncResp&&) = delete;
178
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200179 void addMetadata(const nlohmann::json& sensorObject,
Ed Tanousc1d019a2022-08-06 09:36:06 -0700180 const std::string& dbusPath)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200181 {
182 if (metadata)
183 {
Ed Tanousc1d019a2022-08-06 09:36:06 -0700184 metadata->emplace_back(SensorData{
185 sensorObject["Name"], sensorObject["@odata.id"], dbusPath});
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200186 }
187 }
188
189 void updateUri(const std::string& name, const std::string& uri)
190 {
191 if (metadata)
192 {
193 for (auto& sensor : *metadata)
194 {
195 if (sensor.name == name)
196 {
197 sensor.uri = uri;
198 }
199 }
200 }
201 }
202
zhanghch058d1b46d2021-04-01 11:18:24 +0800203 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200204 const std::string chassisId;
Ed Tanouscf9e4172022-12-21 09:30:16 -0800205 const std::span<const std::string_view> types;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200206 const std::string chassisSubNode;
Nan Zhou928fefb2022-03-28 08:45:00 -0700207 const bool efficientExpand;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200208
209 private:
210 std::optional<std::vector<SensorData>> metadata;
211 DataCompleteCb dataComplete;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100212};
213
Janet Adkinsc9563602024-08-28 11:37:46 -0500214using InventoryItem = sensor_utils::InventoryItem;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500215
216/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530217 * @brief Get objects with connection necessary for sensors
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200218 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100219 * @param sensorNames Sensors retrieved from chassis
220 * @param callback Callback for processing gathered connections
221 */
222template <typename Callback>
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530223void getObjectsWithConnection(
Ed Tanous81ce6092020-12-17 16:54:55 +0000224 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +0000225 const std::shared_ptr<std::set<std::string>>& sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530226 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700227{
Ed Tanous62598e32023-07-17 17:06:25 -0700228 BMCWEB_LOG_DEBUG("getObjectsWithConnection enter");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700229 const std::string path = "/xyz/openbmc_project/sensors";
George Liue99073f2022-12-09 11:06:16 +0800230 constexpr std::array<std::string_view, 1> interfaces = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700231 "xyz.openbmc_project.Sensor.Value"};
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100232
George Liue99073f2022-12-09 11:06:16 +0800233 // Make call to ObjectMapper to find all sensors objects
234 dbus::utility::getSubTree(
235 path, 2, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700236 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
George Liue99073f2022-12-09 11:06:16 +0800237 sensorNames](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700238 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400239 // Response handler for parsing objects subtree
240 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler enter");
241 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700242 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400243 messages::internalError(sensorsAsyncResp->asyncResp->res);
244 BMCWEB_LOG_ERROR(
245 "getObjectsWithConnection resp_handler: Dbus error {}", ec);
246 return;
247 }
248
249 BMCWEB_LOG_DEBUG("Found {} subtrees", subtree.size());
250
251 // Make unique list of connections only for requested sensor types
252 // and found in the chassis
253 std::set<std::string> connections;
254 std::set<std::pair<std::string, std::string>> objectsWithConnection;
255
256 BMCWEB_LOG_DEBUG("sensorNames list count: {}", sensorNames->size());
257 for (const std::string& tsensor : *sensorNames)
258 {
259 BMCWEB_LOG_DEBUG("Sensor to find: {}", tsensor);
260 }
261
262 for (const std::pair<std::string,
263 std::vector<std::pair<
264 std::string, std::vector<std::string>>>>&
265 object : subtree)
266 {
267 if (sensorNames->find(object.first) != sensorNames->end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700268 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400269 for (const std::pair<std::string, std::vector<std::string>>&
270 objData : object.second)
271 {
272 BMCWEB_LOG_DEBUG("Adding connection: {}",
273 objData.first);
274 connections.insert(objData.first);
275 objectsWithConnection.insert(
276 std::make_pair(object.first, objData.first));
277 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700278 }
279 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400280 BMCWEB_LOG_DEBUG("Found {} connections", connections.size());
281 callback(std::move(connections), std::move(objectsWithConnection));
282 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler exit");
283 });
Ed Tanous62598e32023-07-17 17:06:25 -0700284 BMCWEB_LOG_DEBUG("getObjectsWithConnection exit");
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530285}
286
287/**
288 * @brief Create connections necessary for sensors
289 * @param SensorsAsyncResp Pointer to object holding response data
290 * @param sensorNames Sensors retrieved from chassis
291 * @param callback Callback for processing gathered connections
292 */
293template <typename Callback>
Ed Tanousdaadfb22024-12-20 09:25:54 -0800294void getConnections(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
295 const std::shared_ptr<std::set<std::string>>& sensorNames,
Nan Zhoufe04d492022-06-22 17:10:41 +0000296 Callback&& callback)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530297{
298 auto objectsWithConnectionCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -0700299 [callback = std::forward<Callback>(callback)](
300 const std::set<std::string>& connections,
301 const std::set<std::pair<std::string, std::string>>&
302 /*objectsWithConnection*/) { callback(connections); };
Ed Tanous81ce6092020-12-17 16:54:55 +0000303 getObjectsWithConnection(sensorsAsyncResp, sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530304 std::move(objectsWithConnectionCb));
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100305}
306
307/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700308 * @brief Shrinks the list of sensors for processing
309 * @param SensorsAysncResp The class holding the Redfish response
310 * @param allSensors A list of all the sensors associated to the
311 * chassis element (i.e. baseboard, front panel, etc...)
312 * @param activeSensors A list that is a reduction of the incoming
313 * allSensors list. Eliminate Thermal sensors when a Power request is
314 * made, and eliminate Power sensors when a Thermal request is made.
315 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000316inline void reduceSensorList(
Ed Tanous7f1cc262022-08-09 13:33:57 -0700317 crow::Response& res, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800318 std::span<const std::string_view> sensorTypes,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700319 const std::vector<std::string>* allSensors,
Nan Zhoufe04d492022-06-22 17:10:41 +0000320 const std::shared_ptr<std::set<std::string>>& activeSensors)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700321{
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700322 if ((allSensors == nullptr) || (activeSensors == nullptr))
323 {
Ed Tanous7f1cc262022-08-09 13:33:57 -0700324 messages::resourceNotFound(res, chassisSubNode,
Janet Adkins0c728b42024-08-29 11:09:10 -0500325 chassisSubNode == sensors::thermalNodeStr
Ed Tanous7f1cc262022-08-09 13:33:57 -0700326 ? "Temperatures"
327 : "Voltages");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700328
329 return;
330 }
331 if (allSensors->empty())
332 {
333 // Nothing to do, the activeSensors object is also empty
334 return;
335 }
336
Ed Tanous7f1cc262022-08-09 13:33:57 -0700337 for (std::string_view type : sensorTypes)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700338 {
339 for (const std::string& sensor : *allSensors)
340 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700341 if (sensor.starts_with(type))
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700342 {
343 activeSensors->emplace(sensor);
344 }
345 }
346 }
347}
348
Ed Tanous7f1cc262022-08-09 13:33:57 -0700349/*
350 *Populates the top level collection for a given subnode. Populates
351 *SensorCollection, Power, or Thermal schemas.
352 *
353 * */
354inline void populateChassisNode(nlohmann::json& jsonValue,
355 std::string_view chassisSubNode)
356{
Janet Adkins0c728b42024-08-29 11:09:10 -0500357 if (chassisSubNode == sensors::powerNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700358 {
359 jsonValue["@odata.type"] = "#Power.v1_5_2.Power";
360 }
Janet Adkins0c728b42024-08-29 11:09:10 -0500361 else if (chassisSubNode == sensors::thermalNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700362 {
363 jsonValue["@odata.type"] = "#Thermal.v1_4_0.Thermal";
364 jsonValue["Fans"] = nlohmann::json::array();
365 jsonValue["Temperatures"] = nlohmann::json::array();
366 }
Janet Adkins0c728b42024-08-29 11:09:10 -0500367 else if (chassisSubNode == sensors::sensorsNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700368 {
369 jsonValue["@odata.type"] = "#SensorCollection.SensorCollection";
370 jsonValue["Description"] = "Collection of Sensors for this Chassis";
371 jsonValue["Members"] = nlohmann::json::array();
372 jsonValue["Members@odata.count"] = 0;
373 }
374
Janet Adkins0c728b42024-08-29 11:09:10 -0500375 if (chassisSubNode != sensors::sensorsNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700376 {
377 jsonValue["Id"] = chassisSubNode;
378 }
379 jsonValue["Name"] = chassisSubNode;
380}
381
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700382/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100383 * @brief Retrieves requested chassis sensors and redundancy data from DBus .
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200384 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100385 * @param callback Callback for next step in gathered sensor processing
386 */
387template <typename Callback>
Ed Tanous7f1cc262022-08-09 13:33:57 -0700388void getChassis(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
389 std::string_view chassisId, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800390 std::span<const std::string_view> sensorTypes,
391 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700392{
Ed Tanous62598e32023-07-17 17:06:25 -0700393 BMCWEB_LOG_DEBUG("getChassis enter");
George Liu7a1dbc42022-12-07 16:03:22 +0800394 constexpr std::array<std::string_view, 2> interfaces = {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700395 "xyz.openbmc_project.Inventory.Item.Board",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500396 "xyz.openbmc_project.Inventory.Item.Chassis"};
George Liu7a1dbc42022-12-07 16:03:22 +0800397
398 // Get the Chassis Collection
399 dbus::utility::getSubTreePaths(
400 "/xyz/openbmc_project/inventory", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700401 [callback = std::forward<Callback>(callback), asyncResp,
Ed Tanous7f1cc262022-08-09 13:33:57 -0700402 chassisIdStr{std::string(chassisId)},
Ed Tanous4e0d8782024-09-06 15:16:41 -0700403 chassisSubNode{std::string(chassisSubNode)},
404 sensorTypes](const boost::system::error_code& ec,
405 const dbus::utility::MapperGetSubTreePathsResponse&
406 chassisPaths) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400407 BMCWEB_LOG_DEBUG("getChassis respHandler enter");
408 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700409 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400410 BMCWEB_LOG_ERROR("getChassis respHandler DBUS error: {}", ec);
411 messages::internalError(asyncResp->res);
412 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700413 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400414 const std::string* chassisPath = nullptr;
415 for (const std::string& chassis : chassisPaths)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700416 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400417 sdbusplus::message::object_path path(chassis);
418 std::string chassisName = path.filename();
419 if (chassisName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700420 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400421 BMCWEB_LOG_ERROR("Failed to find '/' in {}", chassis);
422 continue;
423 }
424 if (chassisName == chassisIdStr)
425 {
426 chassisPath = &chassis;
427 break;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700428 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700429 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400430 if (chassisPath == nullptr)
431 {
432 messages::resourceNotFound(asyncResp->res, "Chassis",
433 chassisIdStr);
434 return;
435 }
436 populateChassisNode(asyncResp->res.jsonValue, chassisSubNode);
437
438 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
439 "/redfish/v1/Chassis/{}/{}", chassisIdStr, chassisSubNode);
440
441 // Get the list of all sensors for this Chassis element
442 std::string sensorPath = *chassisPath + "/all_sensors";
443 dbus::utility::getAssociationEndPoints(
Ed Tanous4e0d8782024-09-06 15:16:41 -0700444 sensorPath, [asyncResp, chassisSubNode, sensorTypes,
445 callback = std::forward<Callback>(callback)](
446 const boost::system::error_code& ec2,
447 const dbus::utility::MapperEndPoints&
448 nodeSensorList) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400449 if (ec2)
450 {
451 if (ec2.value() != EBADR)
452 {
453 messages::internalError(asyncResp->res);
454 return;
455 }
456 }
457 const std::shared_ptr<std::set<std::string>>
458 culledSensorList =
459 std::make_shared<std::set<std::string>>();
460 reduceSensorList(asyncResp->res, chassisSubNode,
461 sensorTypes, &nodeSensorList,
462 culledSensorList);
463 BMCWEB_LOG_DEBUG("Finishing with {}",
464 culledSensorList->size());
465 callback(culledSensorList);
466 });
George Liu7a1dbc42022-12-07 16:03:22 +0800467 });
Ed Tanous62598e32023-07-17 17:06:25 -0700468 BMCWEB_LOG_DEBUG("getChassis exit");
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100469}
470
471/**
Ed Tanous1d7c0052022-08-09 12:32:26 -0700472 * @brief Builds a json sensor representation of a sensor.
473 * @param sensorName The name of the sensor to be built
474 * @param sensorType The type (temperature, fan_tach, etc) of the sensor to
475 * build
Ed Tanous8ece0e42024-01-02 13:16:50 -0800476 * @param chassisSubNode The subnode (thermal, sensor, etc) of the sensor
Ed Tanous1d7c0052022-08-09 12:32:26 -0700477 * @param interfacesDict A dictionary of the interfaces and properties of said
478 * interfaces to be built from
479 * @param sensorJson The json object to fill
480 * @param inventoryItem D-Bus inventory item associated with the sensor. Will
481 * be nullptr if no associated inventory item was found.
482 */
483inline void objectInterfacesToJson(
484 const std::string& sensorName, const std::string& sensorType,
Janet Adkins0c728b42024-08-29 11:09:10 -0500485 const sensor_utils::ChassisSubNode chassisSubNode,
Michael Shen80f79a42023-08-24 13:41:53 +0000486 const dbus::utility::DBusInterfacesMap& interfacesDict,
Ed Tanous1d7c0052022-08-09 12:32:26 -0700487 nlohmann::json& sensorJson, InventoryItem* inventoryItem)
488{
Ed Tanous1d7c0052022-08-09 12:32:26 -0700489 for (const auto& [interface, valuesDict] : interfacesDict)
490 {
Janet Adkinsc9563602024-08-28 11:37:46 -0500491 sensor_utils::objectPropertiesToJson(
492 sensorName, sensorType, chassisSubNode, valuesDict, sensorJson,
493 inventoryItem);
Ed Tanous1d7c0052022-08-09 12:32:26 -0700494 }
Ed Tanous62598e32023-07-17 17:06:25 -0700495 BMCWEB_LOG_DEBUG("Added sensor {}", sensorName);
Ed Tanous1d7c0052022-08-09 12:32:26 -0700496}
497
Ed Tanousb5a76932020-09-29 16:16:58 -0700498inline void populateFanRedundancy(
499 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
James Feist8bd25cc2019-03-15 15:14:00 -0700500{
George Liue99073f2022-12-09 11:06:16 +0800501 constexpr std::array<std::string_view, 1> interfaces = {
502 "xyz.openbmc_project.Control.FanRedundancy"};
503 dbus::utility::getSubTree(
504 "/xyz/openbmc_project/control", 2, interfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800505 [sensorsAsyncResp](
George Liue99073f2022-12-09 11:06:16 +0800506 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800507 const dbus::utility::MapperGetSubTreeResponse& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400508 if (ec)
James Feist8bd25cc2019-03-15 15:14:00 -0700509 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400510 return; // don't have to have this interface
James Feist8bd25cc2019-03-15 15:14:00 -0700511 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400512 for (const std::pair<std::string, dbus::utility::MapperServiceMap>&
513 pathPair : resp)
514 {
515 const std::string& path = pathPair.first;
516 const dbus::utility::MapperServiceMap& objDict =
517 pathPair.second;
518 if (objDict.empty())
James Feist8bd25cc2019-03-15 15:14:00 -0700519 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400520 continue; // this should be impossible
James Feist8bd25cc2019-03-15 15:14:00 -0700521 }
522
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400523 const std::string& owner = objDict.begin()->first;
524 dbus::utility::getAssociationEndPoints(
525 path + "/chassis",
526 [path, owner, sensorsAsyncResp](
527 const boost::system::error_code& ec2,
528 const dbus::utility::MapperEndPoints& endpoints) {
529 if (ec2)
James Feist8bd25cc2019-03-15 15:14:00 -0700530 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400531 return; // if they don't have an association we
532 // can't tell what chassis is
James Feist8bd25cc2019-03-15 15:14:00 -0700533 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400534 auto found = std::ranges::find_if(
535 endpoints,
536 [sensorsAsyncResp](const std::string& entry) {
537 return entry.find(
538 sensorsAsyncResp->chassisId) !=
539 std::string::npos;
540 });
541
542 if (found == endpoints.end())
James Feist8bd25cc2019-03-15 15:14:00 -0700543 {
544 return;
545 }
Ed Tanousdeae6a72024-11-11 21:58:57 -0800546 dbus::utility::getAllProperties(
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400547 *crow::connections::systemBus, owner, path,
548 "xyz.openbmc_project.Control.FanRedundancy",
549 [path, sensorsAsyncResp](
550 const boost::system::error_code& ec3,
551 const dbus::utility::DBusPropertiesMap& ret) {
552 if (ec3)
553 {
554 return; // don't have to have this
555 // interface
556 }
James Feist8bd25cc2019-03-15 15:14:00 -0700557
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400558 const uint8_t* allowedFailures = nullptr;
559 const std::vector<std::string>* collection =
560 nullptr;
561 const std::string* status = nullptr;
James Feist8bd25cc2019-03-15 15:14:00 -0700562
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400563 const bool success =
564 sdbusplus::unpackPropertiesNoThrow(
565 dbus_utils::UnpackErrorPrinter(), ret,
566 "AllowedFailures", allowedFailures,
567 "Collection", collection, "Status",
568 status);
James Feist8bd25cc2019-03-15 15:14:00 -0700569
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400570 if (!success)
571 {
572 messages::internalError(
573 sensorsAsyncResp->asyncResp->res);
574 return;
575 }
576
577 if (allowedFailures == nullptr ||
578 collection == nullptr || status == nullptr)
579 {
580 BMCWEB_LOG_ERROR(
581 "Invalid redundancy interface");
582 messages::internalError(
583 sensorsAsyncResp->asyncResp->res);
584 return;
585 }
586
587 sdbusplus::message::object_path objectPath(
588 path);
589 std::string name = objectPath.filename();
590 if (name.empty())
591 {
592 // this should be impossible
593 messages::internalError(
594 sensorsAsyncResp->asyncResp->res);
595 return;
596 }
597 std::ranges::replace(name, '_', ' ');
598
599 std::string health;
600
601 if (status->ends_with("Full"))
602 {
603 health = "OK";
604 }
605 else if (status->ends_with("Degraded"))
606 {
607 health = "Warning";
608 }
609 else
610 {
611 health = "Critical";
612 }
613 nlohmann::json::array_t redfishCollection;
614 const auto& fanRedfish =
615 sensorsAsyncResp->asyncResp->res
616 .jsonValue["Fans"];
617 for (const std::string& item : *collection)
618 {
619 sdbusplus::message::object_path itemPath(
620 item);
621 std::string itemName = itemPath.filename();
622 if (itemName.empty())
623 {
624 continue;
625 }
626 /*
627 todo(ed): merge patch that fixes the names
628 std::replace(itemName.begin(),
629 itemName.end(), '_', ' ');*/
630 auto schemaItem = std::ranges::find_if(
631 fanRedfish,
632 [itemName](const nlohmann::json& fan) {
633 return fan["Name"] == itemName;
634 });
635 if (schemaItem != fanRedfish.end())
636 {
637 nlohmann::json::object_t collectionId;
638 collectionId["@odata.id"] =
639 (*schemaItem)["@odata.id"];
640 redfishCollection.emplace_back(
641 std::move(collectionId));
642 }
643 else
644 {
645 BMCWEB_LOG_ERROR(
646 "failed to find fan in schema");
647 messages::internalError(
648 sensorsAsyncResp->asyncResp->res);
649 return;
650 }
651 }
652
653 size_t minNumNeeded =
654 collection->empty()
655 ? 0
656 : collection->size() - *allowedFailures;
657 nlohmann::json& jResp =
658 sensorsAsyncResp->asyncResp->res
659 .jsonValue["Redundancy"];
660
661 nlohmann::json::object_t redundancy;
662 boost::urls::url url = boost::urls::format(
663 "/redfish/v1/Chassis/{}/{}",
664 sensorsAsyncResp->chassisId,
665 sensorsAsyncResp->chassisSubNode);
666 url.set_fragment(
667 ("/Redundancy"_json_pointer / jResp.size())
668 .to_string());
669 redundancy["@odata.id"] = std::move(url);
670 redundancy["@odata.type"] =
671 "#Redundancy.v1_3_2.Redundancy";
672 redundancy["MinNumNeeded"] = minNumNeeded;
673 redundancy["Mode"] =
674 redundancy::RedundancyType::NPlusM;
675 redundancy["Name"] = name;
676 redundancy["RedundancySet"] = redfishCollection;
677 redundancy["Status"]["Health"] = health;
678 redundancy["Status"]["State"] =
679 resource::State::Enabled;
680
681 jResp.emplace_back(std::move(redundancy));
682 });
683 });
684 }
685 });
James Feist8bd25cc2019-03-15 15:14:00 -0700686}
687
Ed Tanousb5a76932020-09-29 16:16:58 -0700688inline void
Ed Tanous81ce6092020-12-17 16:54:55 +0000689 sortJSONResponse(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700690{
zhanghch058d1b46d2021-04-01 11:18:24 +0800691 nlohmann::json& response = sensorsAsyncResp->asyncResp->res.jsonValue;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700692 std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
Janet Adkins0c728b42024-08-29 11:09:10 -0500693 if (sensorsAsyncResp->chassisSubNode == sensors::powerNodeStr)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700694 {
695 sensorHeaders = {"Voltages", "PowerSupplies"};
696 }
697 for (const std::string& sensorGroup : sensorHeaders)
698 {
699 nlohmann::json::iterator entry = response.find(sensorGroup);
Ed Tanous4e196b92024-09-27 17:45:09 -0700700 if (entry == response.end())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700701 {
Ed Tanous4e196b92024-09-27 17:45:09 -0700702 continue;
703 }
704 nlohmann::json::array_t* arr =
705 entry->get_ptr<nlohmann::json::array_t*>();
706 if (arr == nullptr)
707 {
708 continue;
709 }
710 json_util::sortJsonArrayByKey(*arr, "Name");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700711
Ed Tanous4e196b92024-09-27 17:45:09 -0700712 // add the index counts to the end of each entry
713 size_t count = 0;
714 for (nlohmann::json& sensorJson : *entry)
715 {
716 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
717 if (odata == sensorJson.end())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700718 {
Ed Tanous4e196b92024-09-27 17:45:09 -0700719 continue;
720 }
721 std::string* value = odata->get_ptr<std::string*>();
722 if (value != nullptr)
723 {
724 *value += "/" + std::to_string(count);
725 sensorJson["MemberId"] = std::to_string(count);
726 count++;
727 sensorsAsyncResp->updateUri(sensorJson["Name"], *value);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700728 }
729 }
730 }
731}
732
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100733/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500734 * @brief Finds the inventory item with the specified object path.
735 * @param inventoryItems D-Bus inventory items associated with sensors.
736 * @param invItemObjPath D-Bus object path of inventory item.
737 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500738 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000739inline InventoryItem* findInventoryItem(
Ed Tanousb5a76932020-09-29 16:16:58 -0700740 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500741 const std::string& invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500742{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500743 for (InventoryItem& inventoryItem : *inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500744 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500745 if (inventoryItem.objectPath == invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500746 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500747 return &inventoryItem;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500748 }
749 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500750 return nullptr;
751}
752
753/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500754 * @brief Finds the inventory item associated with the specified sensor.
755 * @param inventoryItems D-Bus inventory items associated with sensors.
756 * @param sensorObjPath D-Bus object path of sensor.
757 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500758 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000759inline InventoryItem* findInventoryItemForSensor(
Ed Tanousb5a76932020-09-29 16:16:58 -0700760 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500761 const std::string& sensorObjPath)
762{
763 for (InventoryItem& inventoryItem : *inventoryItems)
764 {
Ed Tanousdb0d36e2023-06-30 10:37:05 -0700765 if (inventoryItem.sensors.contains(sensorObjPath))
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500766 {
767 return &inventoryItem;
768 }
769 }
770 return nullptr;
771}
772
773/**
Anthony Wilsond5005492019-07-31 16:34:17 -0500774 * @brief Finds the inventory item associated with the specified led path.
775 * @param inventoryItems D-Bus inventory items associated with sensors.
776 * @param ledObjPath D-Bus object path of led.
777 * @return Inventory item within vector, or nullptr if no match found.
778 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400779inline InventoryItem* findInventoryItemForLed(
780 std::vector<InventoryItem>& inventoryItems, const std::string& ledObjPath)
Anthony Wilsond5005492019-07-31 16:34:17 -0500781{
782 for (InventoryItem& inventoryItem : inventoryItems)
783 {
784 if (inventoryItem.ledObjectPath == ledObjPath)
785 {
786 return &inventoryItem;
787 }
788 }
789 return nullptr;
790}
791
792/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500793 * @brief Adds inventory item and associated sensor to specified vector.
794 *
795 * Adds a new InventoryItem to the vector if necessary. Searches for an
796 * existing InventoryItem with the specified object path. If not found, one is
797 * added to the vector.
798 *
799 * Next, the specified sensor is added to the set of sensors associated with the
800 * InventoryItem.
801 *
802 * @param inventoryItems D-Bus inventory items associated with sensors.
803 * @param invItemObjPath D-Bus object path of inventory item.
804 * @param sensorObjPath D-Bus object path of sensor
805 */
Ed Tanousb5a76932020-09-29 16:16:58 -0700806inline void addInventoryItem(
807 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
808 const std::string& invItemObjPath, const std::string& sensorObjPath)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500809{
810 // Look for inventory item in vector
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400811 InventoryItem* inventoryItem =
812 findInventoryItem(inventoryItems, invItemObjPath);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500813
814 // If inventory item doesn't exist in vector, add it
815 if (inventoryItem == nullptr)
816 {
817 inventoryItems->emplace_back(invItemObjPath);
818 inventoryItem = &(inventoryItems->back());
819 }
820
821 // Add sensor to set of sensors associated with inventory item
822 inventoryItem->sensors.emplace(sensorObjPath);
823}
824
825/**
826 * @brief Stores D-Bus data in the specified inventory item.
827 *
828 * Finds D-Bus data in the specified map of interfaces. Stores the data in the
829 * specified InventoryItem.
830 *
831 * This data is later used to provide sensor property values in the JSON
832 * response.
833 *
834 * @param inventoryItem Inventory item where data will be stored.
835 * @param interfacesDict Map containing D-Bus interfaces and their properties
836 * for the specified inventory item.
837 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000838inline void storeInventoryItemData(
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500839 InventoryItem& inventoryItem,
Michael Shen80f79a42023-08-24 13:41:53 +0000840 const dbus::utility::DBusInterfacesMap& interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500841{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500842 // Get properties from Inventory.Item interface
Ed Tanous711ac7a2021-12-20 09:34:41 -0800843
Ed Tanous9eb808c2022-01-25 10:19:23 -0800844 for (const auto& [interface, values] : interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500845 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800846 if (interface == "xyz.openbmc_project.Inventory.Item")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500847 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800848 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500849 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800850 if (name == "Present")
851 {
852 const bool* value = std::get_if<bool>(&dbusValue);
853 if (value != nullptr)
854 {
855 inventoryItem.isPresent = *value;
856 }
857 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500858 }
859 }
Ed Tanous711ac7a2021-12-20 09:34:41 -0800860 // Check if Inventory.Item.PowerSupply interface is present
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500861
Ed Tanous711ac7a2021-12-20 09:34:41 -0800862 if (interface == "xyz.openbmc_project.Inventory.Item.PowerSupply")
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500863 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800864 inventoryItem.isPowerSupply = true;
865 }
866
867 // Get properties from Inventory.Decorator.Asset interface
868 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
869 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800870 for (const auto& [name, dbusValue] : values)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500871 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800872 if (name == "Manufacturer")
873 {
874 const std::string* value =
875 std::get_if<std::string>(&dbusValue);
876 if (value != nullptr)
877 {
878 inventoryItem.manufacturer = *value;
879 }
880 }
881 if (name == "Model")
882 {
883 const std::string* value =
884 std::get_if<std::string>(&dbusValue);
885 if (value != nullptr)
886 {
887 inventoryItem.model = *value;
888 }
889 }
890 if (name == "SerialNumber")
891 {
892 const std::string* value =
893 std::get_if<std::string>(&dbusValue);
894 if (value != nullptr)
895 {
896 inventoryItem.serialNumber = *value;
897 }
898 }
899 if (name == "PartNumber")
900 {
901 const std::string* value =
902 std::get_if<std::string>(&dbusValue);
903 if (value != nullptr)
904 {
905 inventoryItem.partNumber = *value;
906 }
907 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500908 }
909 }
910
Ed Tanous711ac7a2021-12-20 09:34:41 -0800911 if (interface ==
912 "xyz.openbmc_project.State.Decorator.OperationalStatus")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500913 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800914 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500915 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800916 if (name == "Functional")
917 {
918 const bool* value = std::get_if<bool>(&dbusValue);
919 if (value != nullptr)
920 {
921 inventoryItem.isFunctional = *value;
922 }
923 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500924 }
925 }
926 }
927}
928
929/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500930 * @brief Gets D-Bus data for inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500931 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500932 * Uses the specified connections (services) to obtain D-Bus data for inventory
933 * items associated with sensors. Stores the resulting data in the
934 * inventoryItems vector.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500935 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500936 * This data is later used to provide sensor property values in the JSON
937 * response.
938 *
939 * Finds the inventory item data asynchronously. Invokes callback when data has
940 * been obtained.
941 *
942 * The callback must have the following signature:
943 * @code
Anthony Wilsond5005492019-07-31 16:34:17 -0500944 * callback(void)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500945 * @endcode
946 *
947 * This function is called recursively, obtaining data asynchronously from one
948 * connection in each call. This ensures the callback is not invoked until the
949 * last asynchronous function has completed.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500950 *
951 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500952 * @param inventoryItems D-Bus inventory items associated with sensors.
953 * @param invConnections Connections that provide data for the inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500954 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500955 * @param callback Callback to invoke when inventory data has been obtained.
956 * @param invConnectionsIndex Current index in invConnections. Only specified
957 * in recursive calls to this function.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500958 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500959template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -0700960void getInventoryItemsData(
Ed Tanousdaadfb22024-12-20 09:25:54 -0800961 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
962 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
963 const std::shared_ptr<std::set<std::string>>& invConnections,
964 Callback&& callback, size_t invConnectionsIndex = 0)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500965{
Ed Tanous62598e32023-07-17 17:06:25 -0700966 BMCWEB_LOG_DEBUG("getInventoryItemsData enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500967
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500968 // If no more connections left, call callback
969 if (invConnectionsIndex >= invConnections->size())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500970 {
Anthony Wilsond5005492019-07-31 16:34:17 -0500971 callback();
Ed Tanous62598e32023-07-17 17:06:25 -0700972 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500973 return;
974 }
975
976 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +0000977 auto it = invConnections->begin();
978 std::advance(it, invConnectionsIndex);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500979 if (it != invConnections->end())
980 {
981 const std::string& invConnection = *it;
982
George Liu5eb468d2023-06-20 17:03:24 +0800983 // Get all object paths and their interfaces for current connection
984 sdbusplus::message::object_path path("/xyz/openbmc_project/inventory");
985 dbus::utility::getManagedObjects(
986 invConnection, path,
987 [sensorsAsyncResp, inventoryItems, invConnections,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700988 callback = std::forward<Callback>(callback), invConnectionsIndex](
George Liu5eb468d2023-06-20 17:03:24 +0800989 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -0700990 const dbus::utility::ManagedObjectType& resp) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400991 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler enter");
992 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500993 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400994 BMCWEB_LOG_ERROR(
995 "getInventoryItemsData respHandler DBus error {}", ec);
996 messages::internalError(sensorsAsyncResp->asyncResp->res);
997 return;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500998 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500999
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001000 // Loop through returned object paths
1001 for (const auto& objDictEntry : resp)
1002 {
1003 const std::string& objPath =
1004 static_cast<const std::string&>(objDictEntry.first);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001005
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001006 // If this object path is one of the specified inventory
1007 // items
1008 InventoryItem* inventoryItem =
1009 findInventoryItem(inventoryItems, objPath);
1010 if (inventoryItem != nullptr)
1011 {
1012 // Store inventory data in InventoryItem
1013 storeInventoryItemData(*inventoryItem,
1014 objDictEntry.second);
1015 }
1016 }
1017
1018 // Recurse to get inventory item data from next connection
1019 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1020 invConnections, std::move(callback),
1021 invConnectionsIndex + 1);
1022
1023 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler exit");
1024 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001025 }
1026
Ed Tanous62598e32023-07-17 17:06:25 -07001027 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001028}
1029
1030/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001031 * @brief Gets connections that provide D-Bus data for inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001032 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001033 * Gets the D-Bus connections (services) that provide data for the inventory
1034 * items that are associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001035 *
1036 * Finds the connections asynchronously. Invokes callback when information has
1037 * been obtained.
1038 *
1039 * The callback must have the following signature:
1040 * @code
Nan Zhoufe04d492022-06-22 17:10:41 +00001041 * callback(std::shared_ptr<std::set<std::string>> invConnections)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001042 * @endcode
1043 *
1044 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001045 * @param inventoryItems D-Bus inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001046 * @param callback Callback to invoke when connections have been obtained.
1047 */
1048template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001049void getInventoryItemsConnections(
Ed Tanousb5a76932020-09-29 16:16:58 -07001050 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1051 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001052 Callback&& callback)
1053{
Ed Tanous62598e32023-07-17 17:06:25 -07001054 BMCWEB_LOG_DEBUG("getInventoryItemsConnections enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001055
1056 const std::string path = "/xyz/openbmc_project/inventory";
George Liue99073f2022-12-09 11:06:16 +08001057 constexpr std::array<std::string_view, 4> interfaces = {
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001058 "xyz.openbmc_project.Inventory.Item",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001059 "xyz.openbmc_project.Inventory.Item.PowerSupply",
1060 "xyz.openbmc_project.Inventory.Decorator.Asset",
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001061 "xyz.openbmc_project.State.Decorator.OperationalStatus"};
1062
George Liue99073f2022-12-09 11:06:16 +08001063 // Make call to ObjectMapper to find all inventory items
1064 dbus::utility::getSubTree(
1065 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001066 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001067 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001068 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001069 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001070 // Response handler for parsing output from GetSubTree
1071 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler enter");
1072 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001073 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001074 messages::internalError(sensorsAsyncResp->asyncResp->res);
1075 BMCWEB_LOG_ERROR(
1076 "getInventoryItemsConnections respHandler DBus error {}",
1077 ec);
1078 return;
1079 }
1080
1081 // Make unique list of connections for desired inventory items
1082 std::shared_ptr<std::set<std::string>> invConnections =
1083 std::make_shared<std::set<std::string>>();
1084
1085 // Loop through objects from GetSubTree
1086 for (const std::pair<std::string,
1087 std::vector<std::pair<
1088 std::string, std::vector<std::string>>>>&
1089 object : subtree)
1090 {
1091 // Check if object path is one of the specified inventory items
1092 const std::string& objPath = object.first;
1093 if (findInventoryItem(inventoryItems, objPath) != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001094 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001095 // Store all connections to inventory item
1096 for (const std::pair<std::string, std::vector<std::string>>&
1097 objData : object.second)
1098 {
1099 const std::string& invConnection = objData.first;
1100 invConnections->insert(invConnection);
1101 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001102 }
1103 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001104
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001105 callback(invConnections);
1106 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler exit");
1107 });
Ed Tanous62598e32023-07-17 17:06:25 -07001108 BMCWEB_LOG_DEBUG("getInventoryItemsConnections exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001109}
1110
1111/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001112 * @brief Gets associations from sensors to inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001113 *
1114 * Looks for ObjectMapper associations from the specified sensors to related
Anthony Wilsond5005492019-07-31 16:34:17 -05001115 * inventory items. Then finds the associations from those inventory items to
1116 * their LEDs, if any.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001117 *
1118 * Finds the inventory items asynchronously. Invokes callback when information
1119 * has been obtained.
1120 *
1121 * The callback must have the following signature:
1122 * @code
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001123 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001124 * @endcode
1125 *
1126 * @param sensorsAsyncResp Pointer to object holding response data.
1127 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001128 * implements ObjectManager.
1129 * @param callback Callback to invoke when inventory items have been obtained.
1130 */
1131template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001132void getInventoryItemAssociations(
Ed Tanousb5a76932020-09-29 16:16:58 -07001133 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001134 const std::shared_ptr<std::set<std::string>>& sensorNames,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001135 Callback&& callback)
1136{
Ed Tanous62598e32023-07-17 17:06:25 -07001137 BMCWEB_LOG_DEBUG("getInventoryItemAssociations enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001138
George Liu5eb468d2023-06-20 17:03:24 +08001139 // Call GetManagedObjects on the ObjectMapper to get all associations
1140 sdbusplus::message::object_path path("/");
1141 dbus::utility::getManagedObjects(
1142 "xyz.openbmc_project.ObjectMapper", path,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001143 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001144 sensorNames](const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001145 const dbus::utility::ManagedObjectType& resp) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001146 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler enter");
1147 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001148 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001149 BMCWEB_LOG_ERROR(
1150 "getInventoryItemAssociations respHandler DBus error {}",
1151 ec);
1152 messages::internalError(sensorsAsyncResp->asyncResp->res);
1153 return;
1154 }
1155
1156 // Create vector to hold list of inventory items
1157 std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1158 std::make_shared<std::vector<InventoryItem>>();
1159
1160 // Loop through returned object paths
1161 std::string sensorAssocPath;
1162 sensorAssocPath.reserve(128); // avoid memory allocations
1163 for (const auto& objDictEntry : resp)
1164 {
1165 const std::string& objPath =
1166 static_cast<const std::string&>(objDictEntry.first);
1167
1168 // If path is inventory association for one of the specified
1169 // sensors
1170 for (const std::string& sensorName : *sensorNames)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001171 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001172 sensorAssocPath = sensorName;
1173 sensorAssocPath += "/inventory";
1174 if (objPath == sensorAssocPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001175 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001176 // Get Association interface for object path
1177 for (const auto& [interface, values] :
1178 objDictEntry.second)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001179 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001180 if (interface == "xyz.openbmc_project.Association")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001181 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001182 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001183 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001184 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001185 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001186 const std::vector<std::string>*
1187 endpoints = std::get_if<
1188 std::vector<std::string>>(
1189 &value);
1190 if ((endpoints != nullptr) &&
1191 !endpoints->empty())
1192 {
1193 // Add inventory item to vector
1194 const std::string& invItemPath =
1195 endpoints->front();
1196 addInventoryItem(inventoryItems,
1197 invItemPath,
1198 sensorName);
1199 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001200 }
1201 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001202 }
1203 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001204 break;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001205 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001206 }
1207 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001208
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001209 // Now loop through the returned object paths again, this time to
1210 // find the leds associated with the inventory items we just found
1211 std::string inventoryAssocPath;
1212 inventoryAssocPath.reserve(128); // avoid memory allocations
1213 for (const auto& objDictEntry : resp)
Anthony Wilsond5005492019-07-31 16:34:17 -05001214 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001215 const std::string& objPath =
1216 static_cast<const std::string&>(objDictEntry.first);
1217
1218 for (InventoryItem& inventoryItem : *inventoryItems)
Anthony Wilsond5005492019-07-31 16:34:17 -05001219 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001220 inventoryAssocPath = inventoryItem.objectPath;
1221 inventoryAssocPath += "/leds";
1222 if (objPath == inventoryAssocPath)
Anthony Wilsond5005492019-07-31 16:34:17 -05001223 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001224 for (const auto& [interface, values] :
1225 objDictEntry.second)
Anthony Wilsond5005492019-07-31 16:34:17 -05001226 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001227 if (interface == "xyz.openbmc_project.Association")
Anthony Wilsond5005492019-07-31 16:34:17 -05001228 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001229 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001230 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001231 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001232 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001233 const std::vector<std::string>*
1234 endpoints = std::get_if<
1235 std::vector<std::string>>(
1236 &value);
1237 if ((endpoints != nullptr) &&
1238 !endpoints->empty())
1239 {
1240 // Add inventory item to vector
1241 // Store LED path in inventory item
1242 const std::string& ledPath =
1243 endpoints->front();
1244 inventoryItem.ledObjectPath =
1245 ledPath;
1246 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001247 }
1248 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001249 }
1250 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001251
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001252 break;
1253 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001254 }
1255 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001256 callback(inventoryItems);
1257 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler exit");
1258 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001259
Ed Tanous62598e32023-07-17 17:06:25 -07001260 BMCWEB_LOG_DEBUG("getInventoryItemAssociations exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001261}
1262
1263/**
Anthony Wilsond5005492019-07-31 16:34:17 -05001264 * @brief Gets D-Bus data for inventory item leds associated with sensors.
1265 *
1266 * Uses the specified connections (services) to obtain D-Bus data for inventory
1267 * item leds associated with sensors. Stores the resulting data in the
1268 * inventoryItems vector.
1269 *
1270 * This data is later used to provide sensor property values in the JSON
1271 * response.
1272 *
1273 * Finds the inventory item led data asynchronously. Invokes callback when data
1274 * has been obtained.
1275 *
1276 * The callback must have the following signature:
1277 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001278 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001279 * @endcode
1280 *
1281 * This function is called recursively, obtaining data asynchronously from one
1282 * connection in each call. This ensures the callback is not invoked until the
1283 * last asynchronous function has completed.
1284 *
1285 * @param sensorsAsyncResp Pointer to object holding response data.
1286 * @param inventoryItems D-Bus inventory items associated with sensors.
1287 * @param ledConnections Connections that provide data for the inventory leds.
1288 * @param callback Callback to invoke when inventory data has been obtained.
1289 * @param ledConnectionsIndex Current index in ledConnections. Only specified
1290 * in recursive calls to this function.
1291 */
1292template <typename Callback>
1293void getInventoryLedData(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001294 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1295 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
1296 const std::shared_ptr<std::map<std::string, std::string>>& ledConnections,
Anthony Wilsond5005492019-07-31 16:34:17 -05001297 Callback&& callback, size_t ledConnectionsIndex = 0)
1298{
Ed Tanous62598e32023-07-17 17:06:25 -07001299 BMCWEB_LOG_DEBUG("getInventoryLedData enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001300
1301 // If no more connections left, call callback
1302 if (ledConnectionsIndex >= ledConnections->size())
1303 {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001304 callback();
Ed Tanous62598e32023-07-17 17:06:25 -07001305 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001306 return;
1307 }
1308
1309 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +00001310 auto it = ledConnections->begin();
1311 std::advance(it, ledConnectionsIndex);
Anthony Wilsond5005492019-07-31 16:34:17 -05001312 if (it != ledConnections->end())
1313 {
1314 const std::string& ledPath = (*it).first;
1315 const std::string& ledConnection = (*it).second;
1316 // Response handler for Get State property
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001317 auto respHandler =
1318 [sensorsAsyncResp, inventoryItems, ledConnections, ledPath,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001319 callback = std::forward<Callback>(callback),
1320 ledConnectionsIndex](const boost::system::error_code& ec,
1321 const std::string& state) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001322 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler enter");
1323 if (ec)
1324 {
1325 BMCWEB_LOG_ERROR(
1326 "getInventoryLedData respHandler DBus error {}", ec);
1327 messages::internalError(sensorsAsyncResp->asyncResp->res);
1328 return;
1329 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001330
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001331 BMCWEB_LOG_DEBUG("Led state: {}", state);
1332 // Find inventory item with this LED object path
1333 InventoryItem* inventoryItem =
1334 findInventoryItemForLed(*inventoryItems, ledPath);
1335 if (inventoryItem != nullptr)
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001336 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001337 // Store LED state in InventoryItem
1338 if (state.ends_with("On"))
1339 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001340 inventoryItem->ledState = sensor_utils::LedState::ON;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001341 }
1342 else if (state.ends_with("Blink"))
1343 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001344 inventoryItem->ledState = sensor_utils::LedState::BLINK;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001345 }
1346 else if (state.ends_with("Off"))
1347 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001348 inventoryItem->ledState = sensor_utils::LedState::OFF;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001349 }
1350 else
1351 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001352 inventoryItem->ledState =
1353 sensor_utils::LedState::UNKNOWN;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001354 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001355 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001356
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001357 // Recurse to get LED data from next connection
1358 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1359 ledConnections, std::move(callback),
1360 ledConnectionsIndex + 1);
Anthony Wilsond5005492019-07-31 16:34:17 -05001361
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001362 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler exit");
1363 };
Anthony Wilsond5005492019-07-31 16:34:17 -05001364
1365 // Get the State property for the current LED
Ed Tanousdeae6a72024-11-11 21:58:57 -08001366 dbus::utility::getProperty<std::string>(
1367 ledConnection, ledPath, "xyz.openbmc_project.Led.Physical", "State",
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001368 std::move(respHandler));
Anthony Wilsond5005492019-07-31 16:34:17 -05001369 }
1370
Ed Tanous62598e32023-07-17 17:06:25 -07001371 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001372}
1373
1374/**
1375 * @brief Gets LED data for LEDs associated with given inventory items.
1376 *
1377 * Gets the D-Bus connections (services) that provide LED data for the LEDs
1378 * associated with the specified inventory items. Then gets the LED data from
1379 * each connection and stores it in the inventory item.
1380 *
1381 * This data is later used to provide sensor property values in the JSON
1382 * response.
1383 *
1384 * Finds the LED data asynchronously. Invokes callback when information has
1385 * been obtained.
1386 *
1387 * The callback must have the following signature:
1388 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001389 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001390 * @endcode
1391 *
1392 * @param sensorsAsyncResp Pointer to object holding response data.
1393 * @param inventoryItems D-Bus inventory items associated with sensors.
1394 * @param callback Callback to invoke when inventory items have been obtained.
1395 */
1396template <typename Callback>
1397void getInventoryLeds(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001398 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1399 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Anthony Wilsond5005492019-07-31 16:34:17 -05001400 Callback&& callback)
1401{
Ed Tanous62598e32023-07-17 17:06:25 -07001402 BMCWEB_LOG_DEBUG("getInventoryLeds enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001403
1404 const std::string path = "/xyz/openbmc_project";
George Liue99073f2022-12-09 11:06:16 +08001405 constexpr std::array<std::string_view, 1> interfaces = {
Anthony Wilsond5005492019-07-31 16:34:17 -05001406 "xyz.openbmc_project.Led.Physical"};
1407
George Liue99073f2022-12-09 11:06:16 +08001408 // Make call to ObjectMapper to find all inventory items
1409 dbus::utility::getSubTree(
1410 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001411 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001412 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001413 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001414 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001415 // Response handler for parsing output from GetSubTree
1416 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler enter");
1417 if (ec)
Anthony Wilsond5005492019-07-31 16:34:17 -05001418 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001419 messages::internalError(sensorsAsyncResp->asyncResp->res);
1420 BMCWEB_LOG_ERROR("getInventoryLeds respHandler DBus error {}",
1421 ec);
1422 return;
Anthony Wilsond5005492019-07-31 16:34:17 -05001423 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001424
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001425 // Build map of LED object paths to connections
1426 std::shared_ptr<std::map<std::string, std::string>> ledConnections =
1427 std::make_shared<std::map<std::string, std::string>>();
1428
1429 // Loop through objects from GetSubTree
1430 for (const std::pair<std::string,
1431 std::vector<std::pair<
1432 std::string, std::vector<std::string>>>>&
1433 object : subtree)
1434 {
1435 // Check if object path is LED for one of the specified
1436 // inventory items
1437 const std::string& ledPath = object.first;
1438 if (findInventoryItemForLed(*inventoryItems, ledPath) !=
1439 nullptr)
1440 {
1441 // Add mapping from ledPath to connection
1442 const std::string& connection =
1443 object.second.begin()->first;
1444 (*ledConnections)[ledPath] = connection;
1445 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", ledPath,
1446 connection);
1447 }
1448 }
1449
1450 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1451 ledConnections, std::move(callback));
1452 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler exit");
1453 });
Ed Tanous62598e32023-07-17 17:06:25 -07001454 BMCWEB_LOG_DEBUG("getInventoryLeds exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001455}
1456
1457/**
Gunnar Mills42cbe532019-08-15 15:26:54 -05001458 * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent
1459 *
1460 * Uses the specified connections (services) (currently assumes just one) to
1461 * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in
1462 * the inventoryItems vector. Only stores data in Power Supply inventoryItems.
1463 *
1464 * This data is later used to provide sensor property values in the JSON
1465 * response.
1466 *
1467 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1468 * when data has been obtained.
1469 *
1470 * The callback must have the following signature:
1471 * @code
1472 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1473 * @endcode
1474 *
1475 * @param sensorsAsyncResp Pointer to object holding response data.
1476 * @param inventoryItems D-Bus inventory items associated with sensors.
1477 * @param psAttributesConnections Connections that provide data for the Power
1478 * Supply Attributes
1479 * @param callback Callback to invoke when data has been obtained.
1480 */
1481template <typename Callback>
1482void getPowerSupplyAttributesData(
Ed Tanousb5a76932020-09-29 16:16:58 -07001483 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Ed Tanousdaadfb22024-12-20 09:25:54 -08001484 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001485 const std::map<std::string, std::string>& psAttributesConnections,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001486 Callback&& callback)
1487{
Ed Tanous62598e32023-07-17 17:06:25 -07001488 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001489
1490 if (psAttributesConnections.empty())
1491 {
Ed Tanous62598e32023-07-17 17:06:25 -07001492 BMCWEB_LOG_DEBUG("Can't find PowerSupplyAttributes, no connections!");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001493 callback(inventoryItems);
1494 return;
1495 }
1496
1497 // Assuming just one connection (service) for now
Nan Zhoufe04d492022-06-22 17:10:41 +00001498 auto it = psAttributesConnections.begin();
Gunnar Mills42cbe532019-08-15 15:26:54 -05001499
1500 const std::string& psAttributesPath = (*it).first;
1501 const std::string& psAttributesConnection = (*it).second;
1502
1503 // Response handler for Get DeratingFactor property
Patrick Williams5a39f772023-10-20 11:20:21 -05001504 auto respHandler = [sensorsAsyncResp, inventoryItems,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001505 callback = std::forward<Callback>(callback)](
Patrick Williams5a39f772023-10-20 11:20:21 -05001506 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001507 uint32_t value) mutable {
Ed Tanous62598e32023-07-17 17:06:25 -07001508 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001509 if (ec)
1510 {
Ed Tanous62598e32023-07-17 17:06:25 -07001511 BMCWEB_LOG_ERROR(
1512 "getPowerSupplyAttributesData respHandler DBus error {}", ec);
zhanghch058d1b46d2021-04-01 11:18:24 +08001513 messages::internalError(sensorsAsyncResp->asyncResp->res);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001514 return;
1515 }
1516
Ed Tanous62598e32023-07-17 17:06:25 -07001517 BMCWEB_LOG_DEBUG("PS EfficiencyPercent value: {}", value);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001518 // Store value in Power Supply Inventory Items
1519 for (InventoryItem& inventoryItem : *inventoryItems)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001520 {
Ed Tanous55f79e62022-01-25 11:26:16 -08001521 if (inventoryItem.isPowerSupply)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001522 {
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001523 inventoryItem.powerSupplyEfficiencyPercent =
1524 static_cast<int>(value);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001525 }
1526 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001527
Ed Tanous62598e32023-07-17 17:06:25 -07001528 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001529 callback(inventoryItems);
1530 };
1531
1532 // Get the DeratingFactor property for the PowerSupplyAttributes
1533 // Currently only property on the interface/only one we care about
Ed Tanousdeae6a72024-11-11 21:58:57 -08001534 dbus::utility::getProperty<uint32_t>(
1535 psAttributesConnection, psAttributesPath,
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001536 "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
1537 std::move(respHandler));
Gunnar Mills42cbe532019-08-15 15:26:54 -05001538
Ed Tanous62598e32023-07-17 17:06:25 -07001539 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001540}
1541
1542/**
1543 * @brief Gets the Power Supply Attributes such as EfficiencyPercent
1544 *
1545 * Gets the D-Bus connection (service) that provides Power Supply Attributes
1546 * data. Then gets the Power Supply Attributes data from the connection
1547 * (currently just assumes 1 connection) and stores the data in the inventory
1548 * item.
1549 *
1550 * This data is later used to provide sensor property values in the JSON
1551 * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish.
1552 *
1553 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1554 * when information has been obtained.
1555 *
1556 * The callback must have the following signature:
1557 * @code
1558 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1559 * @endcode
1560 *
1561 * @param sensorsAsyncResp Pointer to object holding response data.
1562 * @param inventoryItems D-Bus inventory items associated with sensors.
1563 * @param callback Callback to invoke when data has been obtained.
1564 */
1565template <typename Callback>
1566void getPowerSupplyAttributes(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001567 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1568 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001569 Callback&& callback)
1570{
Ed Tanous62598e32023-07-17 17:06:25 -07001571 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001572
1573 // Only need the power supply attributes when the Power Schema
Janet Adkins0c728b42024-08-29 11:09:10 -05001574 if (sensorsAsyncResp->chassisSubNode != sensors::powerNodeStr)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001575 {
Ed Tanous62598e32023-07-17 17:06:25 -07001576 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit since not Power");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001577 callback(inventoryItems);
1578 return;
1579 }
1580
George Liue99073f2022-12-09 11:06:16 +08001581 constexpr std::array<std::string_view, 1> interfaces = {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001582 "xyz.openbmc_project.Control.PowerSupplyAttributes"};
1583
George Liue99073f2022-12-09 11:06:16 +08001584 // Make call to ObjectMapper to find the PowerSupplyAttributes service
1585 dbus::utility::getSubTree(
1586 "/xyz/openbmc_project", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001587 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001588 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001589 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001590 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001591 // Response handler for parsing output from GetSubTree
1592 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler enter");
1593 if (ec)
1594 {
1595 messages::internalError(sensorsAsyncResp->asyncResp->res);
1596 BMCWEB_LOG_ERROR(
1597 "getPowerSupplyAttributes respHandler DBus error {}", ec);
1598 return;
1599 }
1600 if (subtree.empty())
1601 {
1602 BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
1603 callback(inventoryItems);
1604 return;
1605 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001606
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001607 // Currently we only support 1 power supply attribute, use this for
1608 // all the power supplies. Build map of object path to connection.
1609 // Assume just 1 connection and 1 path for now.
1610 std::map<std::string, std::string> psAttributesConnections;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001611
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001612 if (subtree[0].first.empty() || subtree[0].second.empty())
1613 {
1614 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1615 callback(inventoryItems);
1616 return;
1617 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001618
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001619 const std::string& psAttributesPath = subtree[0].first;
1620 const std::string& connection = subtree[0].second.begin()->first;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001621
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001622 if (connection.empty())
1623 {
1624 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1625 callback(inventoryItems);
1626 return;
1627 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001628
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001629 psAttributesConnections[psAttributesPath] = connection;
1630 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", psAttributesPath,
1631 connection);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001632
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001633 getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems,
1634 psAttributesConnections,
1635 std::move(callback));
1636 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler exit");
1637 });
Ed Tanous62598e32023-07-17 17:06:25 -07001638 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001639}
1640
1641/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001642 * @brief Gets inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001643 *
1644 * Finds the inventory items that are associated with the specified sensors.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001645 * Then gets D-Bus data for the inventory items, such as presence and VPD.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001646 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001647 * This data is later used to provide sensor property values in the JSON
1648 * response.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001649 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001650 * Finds the inventory items asynchronously. Invokes callback when the
1651 * inventory items have been obtained.
1652 *
1653 * The callback must have the following signature:
1654 * @code
1655 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1656 * @endcode
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001657 *
1658 * @param sensorsAsyncResp Pointer to object holding response data.
1659 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001660 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001661 * @param callback Callback to invoke when inventory items have been obtained.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001662 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001663template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001664inline void
Ed Tanousdaadfb22024-12-20 09:25:54 -08001665 getInventoryItems(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1666 const std::shared_ptr<std::set<std::string>>& sensorNames,
Ed Tanousd0090732022-10-04 17:22:56 -07001667 Callback&& callback)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001668{
Ed Tanous62598e32023-07-17 17:06:25 -07001669 BMCWEB_LOG_DEBUG("getInventoryItems enter");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001670 auto getInventoryItemAssociationsCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -07001671 [sensorsAsyncResp, callback = std::forward<Callback>(callback)](
Ed Tanousdaadfb22024-12-20 09:25:54 -08001672 const std::shared_ptr<std::vector<InventoryItem>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07001673 inventoryItems) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001674 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb enter");
1675 auto getInventoryItemsConnectionsCb =
1676 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001677 callback = std::forward<Callback>(callback)](
Ed Tanousdaadfb22024-12-20 09:25:54 -08001678 const std::shared_ptr<std::set<std::string>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07001679 invConnections) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001680 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb enter");
1681 auto getInventoryItemsDataCb =
1682 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001683 callback =
1684 std::forward<Callback>(callback)]() mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001685 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001686
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001687 auto getInventoryLedsCb =
1688 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001689 callback = std::forward<Callback>(
1690 callback)]() mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001691 BMCWEB_LOG_DEBUG(
1692 "getInventoryLedsCb enter");
1693 // Find Power Supply Attributes and get the
1694 // data
1695 getPowerSupplyAttributes(
1696 sensorsAsyncResp, inventoryItems,
1697 std::move(callback));
1698 BMCWEB_LOG_DEBUG("getInventoryLedsCb exit");
1699 };
1700
1701 // Find led connections and get the data
1702 getInventoryLeds(sensorsAsyncResp, inventoryItems,
1703 std::move(getInventoryLedsCb));
1704 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb exit");
1705 };
1706
1707 // Get inventory item data from connections
1708 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1709 invConnections,
1710 std::move(getInventoryItemsDataCb));
1711 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001712 };
1713
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001714 // Get connections that provide inventory item data
1715 getInventoryItemsConnections(
1716 sensorsAsyncResp, inventoryItems,
1717 std::move(getInventoryItemsConnectionsCb));
1718 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001719 };
1720
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001721 // Get associations from sensors to inventory items
Ed Tanousd0090732022-10-04 17:22:56 -07001722 getInventoryItemAssociations(sensorsAsyncResp, sensorNames,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001723 std::move(getInventoryItemAssociationsCb));
Ed Tanous62598e32023-07-17 17:06:25 -07001724 BMCWEB_LOG_DEBUG("getInventoryItems exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001725}
1726
1727/**
1728 * @brief Returns JSON PowerSupply object for the specified inventory item.
1729 *
1730 * Searches for a JSON PowerSupply object that matches the specified inventory
1731 * item. If one is not found, a new PowerSupply object is added to the JSON
1732 * array.
1733 *
1734 * Multiple sensors are often associated with one power supply inventory item.
1735 * As a result, multiple sensor values are stored in one JSON PowerSupply
1736 * object.
1737 *
1738 * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1739 * @param inventoryItem Inventory item for the power supply.
1740 * @param chassisId Chassis that contains the power supply.
1741 * @return JSON PowerSupply object for the specified inventory item.
1742 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001743inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001744 const InventoryItem& inventoryItem,
1745 const std::string& chassisId)
1746{
Ed Tanous18f8f602023-07-18 10:07:23 -07001747 std::string nameS;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001748 nameS.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001749 std::ranges::replace_copy(inventoryItem.name, nameS.begin(), '_', ' ');
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001750 // Check if matching PowerSupply object already exists in JSON array
1751 for (nlohmann::json& powerSupply : powerSupplyArray)
1752 {
Ed Tanous18f8f602023-07-18 10:07:23 -07001753 nlohmann::json::iterator nameIt = powerSupply.find("Name");
1754 if (nameIt == powerSupply.end())
1755 {
1756 continue;
1757 }
1758 const std::string* name = nameIt->get_ptr<std::string*>();
1759 if (name == nullptr)
1760 {
1761 continue;
1762 }
1763 if (nameS == *name)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001764 {
1765 return powerSupply;
1766 }
1767 }
1768
1769 // Add new PowerSupply object to JSON array
1770 powerSupplyArray.push_back({});
1771 nlohmann::json& powerSupply = powerSupplyArray.back();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001772 boost::urls::url url =
1773 boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
Willy Tueddfc432022-09-26 16:46:38 +00001774 url.set_fragment(("/PowerSupplies"_json_pointer).to_string());
1775 powerSupply["@odata.id"] = std::move(url);
Ed Tanous18f8f602023-07-18 10:07:23 -07001776 std::string escaped;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001777 escaped.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001778 std::ranges::replace_copy(inventoryItem.name, escaped.begin(), '_', ' ');
1779 powerSupply["Name"] = std::move(escaped);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001780 powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1781 powerSupply["Model"] = inventoryItem.model;
1782 powerSupply["PartNumber"] = inventoryItem.partNumber;
1783 powerSupply["SerialNumber"] = inventoryItem.serialNumber;
Janet Adkinsc9563602024-08-28 11:37:46 -05001784 sensor_utils::setLedState(powerSupply, &inventoryItem);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001785
Gunnar Mills42cbe532019-08-15 15:26:54 -05001786 if (inventoryItem.powerSupplyEfficiencyPercent >= 0)
1787 {
1788 powerSupply["EfficiencyPercent"] =
1789 inventoryItem.powerSupplyEfficiencyPercent;
1790 }
1791
Janet Adkinsc9563602024-08-28 11:37:46 -05001792 powerSupply["Status"]["State"] =
1793 sensor_utils::getState(&inventoryItem, true);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001794 const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1795 powerSupply["Status"]["Health"] = health;
1796
1797 return powerSupply;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001798}
1799
1800/**
Shawn McCarneyde629b62019-03-08 10:42:51 -06001801 * @brief Gets the values of the specified sensors.
1802 *
1803 * Stores the results as JSON in the SensorsAsyncResp.
1804 *
1805 * Gets the sensor values asynchronously. Stores the results later when the
1806 * information has been obtained.
1807 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001808 * The sensorNames set contains all requested sensors for the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001809 *
1810 * To minimize the number of DBus calls, the DBus method
1811 * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1812 * values of all sensors provided by a connection (service).
1813 *
1814 * The connections set contains all the connections that provide sensor values.
1815 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001816 * The InventoryItem vector contains D-Bus inventory items associated with the
1817 * sensors. Inventory item data is needed for some Redfish sensor properties.
1818 *
Shawn McCarneyde629b62019-03-08 10:42:51 -06001819 * @param SensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001820 * @param sensorNames All requested sensors within the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001821 * @param connections Connections that provide sensor values.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001822 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001823 * @param inventoryItems Inventory items associated with the sensors.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001824 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001825inline void getSensorData(
Ed Tanous81ce6092020-12-17 16:54:55 +00001826 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001827 const std::shared_ptr<std::set<std::string>>& sensorNames,
1828 const std::set<std::string>& connections,
Ed Tanousb5a76932020-09-29 16:16:58 -07001829 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001830{
Ed Tanous62598e32023-07-17 17:06:25 -07001831 BMCWEB_LOG_DEBUG("getSensorData enter");
Shawn McCarneyde629b62019-03-08 10:42:51 -06001832 // Get managed objects from all services exposing sensors
1833 for (const std::string& connection : connections)
1834 {
George Liu5eb468d2023-06-20 17:03:24 +08001835 sdbusplus::message::object_path sensorPath(
1836 "/xyz/openbmc_project/sensors");
1837 dbus::utility::getManagedObjects(
1838 connection, sensorPath,
Ed Tanous002d39b2022-05-31 08:59:27 -07001839 [sensorsAsyncResp, sensorNames,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001840 inventoryItems](const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -07001841 const dbus::utility::ManagedObjectType& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001842 BMCWEB_LOG_DEBUG("getManagedObjectsCb enter");
1843 if (ec)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001844 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001845 BMCWEB_LOG_ERROR("getManagedObjectsCb DBUS error: {}", ec);
1846 messages::internalError(sensorsAsyncResp->asyncResp->res);
1847 return;
1848 }
Janet Adkins0c728b42024-08-29 11:09:10 -05001849 auto chassisSubNode = sensor_utils::chassisSubNodeFromString(
1850 sensorsAsyncResp->chassisSubNode);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001851 // Go through all objects and update response with sensor data
1852 for (const auto& objDictEntry : resp)
1853 {
1854 const std::string& objPath =
1855 static_cast<const std::string&>(objDictEntry.first);
1856 BMCWEB_LOG_DEBUG("getManagedObjectsCb parsing object {}",
Ed Tanous62598e32023-07-17 17:06:25 -07001857 objPath);
Shawn McCarneyde629b62019-03-08 10:42:51 -06001858
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001859 std::vector<std::string> split;
1860 // Reserve space for
1861 // /xyz/openbmc_project/sensors/<name>/<subname>
1862 split.reserve(6);
1863 // NOLINTNEXTLINE
1864 bmcweb::split(split, objPath, '/');
1865 if (split.size() < 6)
Nan Zhou928fefb2022-03-28 08:45:00 -07001866 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001867 BMCWEB_LOG_ERROR("Got path that isn't long enough {}",
1868 objPath);
1869 continue;
Nan Zhou928fefb2022-03-28 08:45:00 -07001870 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001871 // These indexes aren't intuitive, as split puts an empty
1872 // string at the beginning
1873 const std::string& sensorType = split[4];
1874 const std::string& sensorName = split[5];
1875 BMCWEB_LOG_DEBUG("sensorName {} sensorType {}", sensorName,
1876 sensorType);
1877 if (sensorNames->find(objPath) == sensorNames->end())
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001878 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001879 BMCWEB_LOG_DEBUG("{} not in sensor list ", sensorName);
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001880 continue;
1881 }
1882
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001883 // Find inventory item (if any) associated with sensor
1884 InventoryItem* inventoryItem =
1885 findInventoryItemForSensor(inventoryItems, objPath);
1886
1887 const std::string& sensorSchema =
1888 sensorsAsyncResp->chassisSubNode;
1889
1890 nlohmann::json* sensorJson = nullptr;
1891
Janet Adkins0c728b42024-08-29 11:09:10 -05001892 if (sensorSchema == sensors::sensorsNodeStr &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001893 !sensorsAsyncResp->efficientExpand)
Nan Zhou928fefb2022-03-28 08:45:00 -07001894 {
Janet Adkins1516c212024-08-14 13:22:41 -05001895 std::string sensorId =
1896 redfish::sensor_utils::getSensorId(sensorName,
1897 sensorType);
Ed Tanous677bb752022-09-15 10:52:19 -07001898
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001899 sensorsAsyncResp->asyncResp->res
1900 .jsonValue["@odata.id"] = boost::urls::format(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001901 "/redfish/v1/Chassis/{}/{}/{}",
Ed Tanous677bb752022-09-15 10:52:19 -07001902 sensorsAsyncResp->chassisId,
1903 sensorsAsyncResp->chassisSubNode, sensorId);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001904 sensorJson =
1905 &(sensorsAsyncResp->asyncResp->res.jsonValue);
Nan Zhou928fefb2022-03-28 08:45:00 -07001906 }
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001907 else
1908 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001909 std::string fieldName;
1910 if (sensorsAsyncResp->efficientExpand)
1911 {
1912 fieldName = "Members";
1913 }
1914 else if (sensorType == "temperature")
1915 {
1916 fieldName = "Temperatures";
1917 }
1918 else if (sensorType == "fan" ||
1919 sensorType == "fan_tach" ||
1920 sensorType == "fan_pwm")
1921 {
1922 fieldName = "Fans";
1923 }
1924 else if (sensorType == "voltage")
1925 {
1926 fieldName = "Voltages";
1927 }
1928 else if (sensorType == "power")
1929 {
1930 if (sensorName == "total_power")
1931 {
1932 fieldName = "PowerControl";
1933 }
1934 else if ((inventoryItem != nullptr) &&
1935 (inventoryItem->isPowerSupply))
1936 {
1937 fieldName = "PowerSupplies";
1938 }
1939 else
1940 {
1941 // Other power sensors are in SensorCollection
1942 continue;
1943 }
1944 }
1945 else
1946 {
1947 BMCWEB_LOG_ERROR(
1948 "Unsure how to handle sensorType {}",
1949 sensorType);
1950 continue;
1951 }
1952
1953 nlohmann::json& tempArray =
1954 sensorsAsyncResp->asyncResp->res
1955 .jsonValue[fieldName];
1956 if (fieldName == "PowerControl")
1957 {
1958 if (tempArray.empty())
1959 {
1960 // Put multiple "sensors" into a single
1961 // PowerControl. Follows MemberId naming and
1962 // naming in power.hpp.
1963 nlohmann::json::object_t power;
1964 boost::urls::url url = boost::urls::format(
1965 "/redfish/v1/Chassis/{}/{}",
1966 sensorsAsyncResp->chassisId,
1967 sensorsAsyncResp->chassisSubNode);
1968 url.set_fragment(
1969 (""_json_pointer / fieldName / "0")
1970 .to_string());
1971 power["@odata.id"] = std::move(url);
1972 tempArray.emplace_back(std::move(power));
1973 }
1974 sensorJson = &(tempArray.back());
1975 }
1976 else if (fieldName == "PowerSupplies")
1977 {
1978 if (inventoryItem != nullptr)
1979 {
1980 sensorJson = &(getPowerSupply(
1981 tempArray, *inventoryItem,
1982 sensorsAsyncResp->chassisId));
1983 }
1984 }
1985 else if (fieldName == "Members")
1986 {
Janet Adkins1516c212024-08-14 13:22:41 -05001987 std::string sensorId =
1988 redfish::sensor_utils::getSensorId(sensorName,
1989 sensorType);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001990
1991 nlohmann::json::object_t member;
1992 member["@odata.id"] = boost::urls::format(
1993 "/redfish/v1/Chassis/{}/{}/{}",
1994 sensorsAsyncResp->chassisId,
1995 sensorsAsyncResp->chassisSubNode, sensorId);
1996 tempArray.emplace_back(std::move(member));
1997 sensorJson = &(tempArray.back());
1998 }
1999 else
2000 {
2001 nlohmann::json::object_t member;
2002 boost::urls::url url = boost::urls::format(
2003 "/redfish/v1/Chassis/{}/{}",
2004 sensorsAsyncResp->chassisId,
2005 sensorsAsyncResp->chassisSubNode);
2006 url.set_fragment(
2007 (""_json_pointer / fieldName).to_string());
2008 member["@odata.id"] = std::move(url);
2009 tempArray.emplace_back(std::move(member));
2010 sensorJson = &(tempArray.back());
2011 }
2012 }
2013
2014 if (sensorJson != nullptr)
2015 {
Janet Adkins0c728b42024-08-29 11:09:10 -05002016 objectInterfacesToJson(
2017 sensorName, sensorType, chassisSubNode,
2018 objDictEntry.second, *sensorJson, inventoryItem);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002019
2020 std::string path = "/xyz/openbmc_project/sensors/";
2021 path += sensorType;
2022 path += "/";
2023 path += sensorName;
2024 sensorsAsyncResp->addMetadata(*sensorJson, path);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002025 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002026 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002027 if (sensorsAsyncResp.use_count() == 1)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002028 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002029 sortJSONResponse(sensorsAsyncResp);
Janet Adkins0c728b42024-08-29 11:09:10 -05002030 if (chassisSubNode ==
2031 sensor_utils::ChassisSubNode::sensorsNode &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002032 sensorsAsyncResp->efficientExpand)
2033 {
2034 sensorsAsyncResp->asyncResp->res
2035 .jsonValue["Members@odata.count"] =
2036 sensorsAsyncResp->asyncResp->res
2037 .jsonValue["Members"]
2038 .size();
2039 }
Janet Adkins0c728b42024-08-29 11:09:10 -05002040 else if (chassisSubNode ==
2041 sensor_utils::ChassisSubNode::thermalNode)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002042 {
2043 populateFanRedundancy(sensorsAsyncResp);
2044 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002045 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002046 BMCWEB_LOG_DEBUG("getManagedObjectsCb exit");
2047 });
Ed Tanous23a21a12020-07-25 04:45:05 +00002048 }
Ed Tanous62598e32023-07-17 17:06:25 -07002049 BMCWEB_LOG_DEBUG("getSensorData exit");
Shawn McCarneyde629b62019-03-08 10:42:51 -06002050}
2051
Nan Zhoufe04d492022-06-22 17:10:41 +00002052inline void
2053 processSensorList(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
2054 const std::shared_ptr<std::set<std::string>>& sensorNames)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002055{
Nan Zhoufe04d492022-06-22 17:10:41 +00002056 auto getConnectionCb = [sensorsAsyncResp, sensorNames](
2057 const std::set<std::string>& connections) {
Ed Tanous62598e32023-07-17 17:06:25 -07002058 BMCWEB_LOG_DEBUG("getConnectionCb enter");
Ed Tanousd0090732022-10-04 17:22:56 -07002059 auto getInventoryItemsCb =
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002060 [sensorsAsyncResp, sensorNames, connections](
2061 const std::shared_ptr<std::vector<InventoryItem>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07002062 inventoryItems) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002063 BMCWEB_LOG_DEBUG("getInventoryItemsCb enter");
2064 // Get sensor data and store results in JSON
2065 getSensorData(sensorsAsyncResp, sensorNames, connections,
2066 inventoryItems);
2067 BMCWEB_LOG_DEBUG("getInventoryItemsCb exit");
2068 };
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002069
Ed Tanousd0090732022-10-04 17:22:56 -07002070 // Get inventory items associated with sensors
2071 getInventoryItems(sensorsAsyncResp, sensorNames,
2072 std::move(getInventoryItemsCb));
2073
Ed Tanous62598e32023-07-17 17:06:25 -07002074 BMCWEB_LOG_DEBUG("getConnectionCb exit");
Ed Tanous002d39b2022-05-31 08:59:27 -07002075 };
2076
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002077 // Get set of connections that provide sensor values
Ed Tanous81ce6092020-12-17 16:54:55 +00002078 getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002079}
2080
Shawn McCarneyde629b62019-03-08 10:42:51 -06002081/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002082 * @brief Entry point for retrieving sensors data related to requested
2083 * chassis.
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02002084 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002085 */
Ed Tanousb5a76932020-09-29 16:16:58 -07002086inline void
Ed Tanous81ce6092020-12-17 16:54:55 +00002087 getChassisData(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002088{
Ed Tanous62598e32023-07-17 17:06:25 -07002089 BMCWEB_LOG_DEBUG("getChassisData enter");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002090 auto getChassisCb =
Ed Tanous81ce6092020-12-17 16:54:55 +00002091 [sensorsAsyncResp](
Nan Zhoufe04d492022-06-22 17:10:41 +00002092 const std::shared_ptr<std::set<std::string>>& sensorNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002093 BMCWEB_LOG_DEBUG("getChassisCb enter");
2094 processSensorList(sensorsAsyncResp, sensorNames);
2095 BMCWEB_LOG_DEBUG("getChassisCb exit");
2096 };
Nan Zhou928fefb2022-03-28 08:45:00 -07002097 // SensorCollection doesn't contain the Redundancy property
Janet Adkins0c728b42024-08-29 11:09:10 -05002098 if (sensorsAsyncResp->chassisSubNode != sensors::sensorsNodeStr)
Nan Zhou928fefb2022-03-28 08:45:00 -07002099 {
2100 sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
2101 nlohmann::json::array();
2102 }
Shawn McCarney26f03892019-05-03 13:20:24 -05002103 // Get set of sensors in chassis
Ed Tanous7f1cc262022-08-09 13:33:57 -07002104 getChassis(sensorsAsyncResp->asyncResp, sensorsAsyncResp->chassisId,
2105 sensorsAsyncResp->chassisSubNode, sensorsAsyncResp->types,
2106 std::move(getChassisCb));
Ed Tanous62598e32023-07-17 17:06:25 -07002107 BMCWEB_LOG_DEBUG("getChassisData exit");
Ed Tanous271584a2019-07-09 16:24:22 -07002108}
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002109
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302110/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002111 * @brief Find the requested sensorName in the list of all sensors supplied by
2112 * the chassis node
2113 *
2114 * @param sensorName The sensor name supplied in the PATCH request
2115 * @param sensorsList The list of sensors managed by the chassis node
2116 * @param sensorsModified The list of sensors that were found as a result of
2117 * repeated calls to this function
2118 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002119inline bool findSensorNameUsingSensorPath(
2120 std::string_view sensorName, const std::set<std::string>& sensorsList,
2121 std::set<std::string>& sensorsModified)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002122{
Nan Zhoufe04d492022-06-22 17:10:41 +00002123 for (const auto& chassisSensor : sensorsList)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002124 {
George Liu28aa8de2021-02-01 15:13:30 +08002125 sdbusplus::message::object_path path(chassisSensor);
Ed Tanousb00dcc22021-02-23 12:52:50 -08002126 std::string thisSensorName = path.filename();
George Liu28aa8de2021-02-01 15:13:30 +08002127 if (thisSensorName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002128 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002129 continue;
2130 }
2131 if (thisSensorName == sensorName)
2132 {
2133 sensorsModified.emplace(chassisSensor);
2134 return true;
2135 }
2136 }
2137 return false;
2138}
2139
2140/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302141 * @brief Entry point for overriding sensor values of given sensor
2142 *
zhanghch058d1b46d2021-04-01 11:18:24 +08002143 * @param sensorAsyncResp response object
Carol Wang4bb3dc32019-10-17 18:15:02 +08002144 * @param allCollections Collections extract from sensors' request patch info
jayaprakash Mutyala91e130a2020-03-04 22:26:38 +00002145 * @param chassisSubNode Chassis Node for which the query has to happen
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302146 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002147inline void setSensorsOverride(
Ed Tanousb5a76932020-09-29 16:16:58 -07002148 const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
Ed Tanous08850572024-03-06 15:09:17 -08002149 std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>&
jayaprakash Mutyala397fd612020-02-06 23:33:34 +00002150 allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302151{
Ed Tanous62598e32023-07-17 17:06:25 -07002152 BMCWEB_LOG_INFO("setSensorsOverride for subNode{}",
2153 sensorAsyncResp->chassisSubNode);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302154
Ed Tanousd02aad32024-02-13 14:43:34 -08002155 std::string_view propertyValueName;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302156 std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302157 std::string memberId;
Ed Tanous543f4402022-01-06 13:12:53 -08002158 double value = 0.0;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302159 for (auto& collectionItems : allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302160 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302161 if (collectionItems.first == "Temperatures")
2162 {
2163 propertyValueName = "ReadingCelsius";
2164 }
2165 else if (collectionItems.first == "Fans")
2166 {
2167 propertyValueName = "Reading";
2168 }
2169 else
2170 {
2171 propertyValueName = "ReadingVolts";
2172 }
2173 for (auto& item : collectionItems.second)
2174 {
Myung Baeafc474a2024-10-09 00:53:29 -07002175 if (!json_util::readJsonObject( //
2176 item, sensorAsyncResp->asyncResp->res, //
2177 "MemberId", memberId, //
2178 propertyValueName, value //
2179 ))
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302180 {
2181 return;
2182 }
2183 overrideMap.emplace(memberId,
2184 std::make_pair(value, collectionItems.first));
2185 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302186 }
Carol Wang4bb3dc32019-10-17 18:15:02 +08002187
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002188 auto getChassisSensorListCb = [sensorAsyncResp, overrideMap,
2189 propertyValueNameStr =
2190 std::string(propertyValueName)](
2191 const std::shared_ptr<
2192 std::set<std::string>>& sensorsList) {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002193 // Match sensor names in the PATCH request to those managed by the
2194 // chassis node
Nan Zhoufe04d492022-06-22 17:10:41 +00002195 const std::shared_ptr<std::set<std::string>> sensorNames =
2196 std::make_shared<std::set<std::string>>();
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302197 for (const auto& item : overrideMap)
2198 {
2199 const auto& sensor = item.first;
Ed Tanousc71d6122022-11-29 14:10:32 -08002200 std::pair<std::string, std::string> sensorNameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002201 redfish::sensor_utils::splitSensorNameAndType(sensor);
Ed Tanousc71d6122022-11-29 14:10:32 -08002202 if (!findSensorNameUsingSensorPath(sensorNameType.second,
2203 *sensorsList, *sensorNames))
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302204 {
Ed Tanous62598e32023-07-17 17:06:25 -07002205 BMCWEB_LOG_INFO("Unable to find memberId {}", item.first);
zhanghch058d1b46d2021-04-01 11:18:24 +08002206 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302207 item.second.second, item.first);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302208 return;
2209 }
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302210 }
2211 // Get the connection to which the memberId belongs
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002212 auto getObjectsWithConnectionCb = [sensorAsyncResp, overrideMap,
2213 propertyValueNameStr](
2214 const std::set<
2215 std::string>& /*connections*/,
2216 const std::set<std::pair<
2217 std::string, std::string>>&
2218 objectsWithConnection) {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002219 if (objectsWithConnection.size() != overrideMap.size())
2220 {
Ed Tanous62598e32023-07-17 17:06:25 -07002221 BMCWEB_LOG_INFO(
2222 "Unable to find all objects with proper connection {} requested {}",
2223 objectsWithConnection.size(), overrideMap.size());
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002224 messages::resourceNotFound(
2225 sensorAsyncResp->asyncResp->res,
Janet Adkins0c728b42024-08-29 11:09:10 -05002226 sensorAsyncResp->chassisSubNode == sensors::thermalNodeStr
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002227 ? "Temperatures"
2228 : "Voltages",
2229 "Count");
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002230 return;
2231 }
2232 for (const auto& item : objectsWithConnection)
2233 {
2234 sdbusplus::message::object_path path(item.first);
2235 std::string sensorName = path.filename();
2236 if (sensorName.empty())
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302237 {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002238 messages::internalError(sensorAsyncResp->asyncResp->res);
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302239 return;
2240 }
Janet Adkins1516c212024-08-14 13:22:41 -05002241 std::string id = redfish::sensor_utils::getSensorId(
2242 sensorName, path.parent_path().filename());
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302243
Ban Feng3f5eb752023-06-29 09:19:20 +08002244 const auto& iterator = overrideMap.find(id);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002245 if (iterator == overrideMap.end())
2246 {
Ed Tanous62598e32023-07-17 17:06:25 -07002247 BMCWEB_LOG_INFO("Unable to find sensor object{}",
2248 item.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002249 messages::internalError(sensorAsyncResp->asyncResp->res);
2250 return;
2251 }
Ginu Georgee93abac2024-06-14 17:35:27 +05302252 setDbusProperty(sensorAsyncResp->asyncResp,
2253 propertyValueNameStr, item.second, item.first,
2254 "xyz.openbmc_project.Sensor.Value", "Value",
Ed Tanousd02aad32024-02-13 14:43:34 -08002255 iterator->second.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002256 }
2257 };
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302258 // Get object with connection for the given sensor name
2259 getObjectsWithConnection(sensorAsyncResp, sensorNames,
2260 std::move(getObjectsWithConnectionCb));
2261 };
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302262 // get full sensor list for the given chassisId and cross verify the sensor.
Ed Tanous7f1cc262022-08-09 13:33:57 -07002263 getChassis(sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId,
2264 sensorAsyncResp->chassisSubNode, sensorAsyncResp->types,
2265 std::move(getChassisSensorListCb));
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302266}
2267
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002268/**
2269 * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus
2270 * path of the sensor.
2271 *
2272 * Function builds valid Redfish response for sensor query of given chassis and
2273 * node. It then builds metadata about Redfish<->D-Bus correlations and provides
2274 * it to caller in a callback.
2275 *
2276 * @param chassis Chassis for which retrieval should be performed
Janet Adkinsc9563602024-08-28 11:37:46 -05002277 * @param node Node (group) of sensors. See sensor_utils::node for supported
2278 * values
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002279 * @param mapComplete Callback to be called with retrieval result
2280 */
Ed Tanous931edc72023-11-01 12:09:07 -07002281template <typename Callback>
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002282inline void retrieveUriToDbusMap(
2283 const std::string& chassis, const std::string& node, Callback&& mapComplete)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002284{
Ed Tanous02da7c52022-02-27 00:09:02 -08002285 decltype(sensors::paths)::const_iterator pathIt =
2286 std::find_if(sensors::paths.cbegin(), sensors::paths.cend(),
2287 [&node](auto&& val) { return val.first == node; });
2288 if (pathIt == sensors::paths.cend())
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002289 {
Ed Tanous62598e32023-07-17 17:06:25 -07002290 BMCWEB_LOG_ERROR("Wrong node provided : {}", node);
Ed Tanous6804b5c2023-10-31 14:50:03 -07002291 std::map<std::string, std::string> noop;
2292 mapComplete(boost::beast::http::status::bad_request, noop);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002293 return;
2294 }
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002295
Nan Zhou72374eb2022-01-27 17:06:51 -08002296 auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002297 auto callback =
2298 [asyncResp, mapCompleteCb = std::forward<Callback>(mapComplete)](
2299 const boost::beast::http::status status,
2300 const std::map<std::string, std::string>& uriToDbus) {
2301 mapCompleteCb(status, uriToDbus);
2302 };
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002303
2304 auto resp = std::make_shared<SensorsAsyncResp>(
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002305 asyncResp, chassis, pathIt->second, node, std::move(callback));
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002306 getChassisData(resp);
2307}
2308
Nan Zhoubacb2162022-04-06 11:28:32 -07002309namespace sensors
2310{
Nan Zhou928fefb2022-03-28 08:45:00 -07002311
Nan Zhoubacb2162022-04-06 11:28:32 -07002312inline void getChassisCallback(
Ed Tanousc1d019a2022-08-06 09:36:06 -07002313 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2314 std::string_view chassisId, std::string_view chassisSubNode,
Nan Zhoufe04d492022-06-22 17:10:41 +00002315 const std::shared_ptr<std::set<std::string>>& sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002316{
Ed Tanous62598e32023-07-17 17:06:25 -07002317 BMCWEB_LOG_DEBUG("getChassisCallback enter ");
Nan Zhoubacb2162022-04-06 11:28:32 -07002318
Ed Tanousc1d019a2022-08-06 09:36:06 -07002319 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
2320 for (const std::string& sensor : *sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002321 {
Ed Tanous62598e32023-07-17 17:06:25 -07002322 BMCWEB_LOG_DEBUG("Adding sensor: {}", sensor);
Nan Zhoubacb2162022-04-06 11:28:32 -07002323
2324 sdbusplus::message::object_path path(sensor);
2325 std::string sensorName = path.filename();
2326 if (sensorName.empty())
2327 {
Ed Tanous62598e32023-07-17 17:06:25 -07002328 BMCWEB_LOG_ERROR("Invalid sensor path: {}", sensor);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002329 messages::internalError(asyncResp->res);
Nan Zhoubacb2162022-04-06 11:28:32 -07002330 return;
2331 }
Ed Tanousc1d019a2022-08-06 09:36:06 -07002332 std::string type = path.parent_path().filename();
Janet Adkins1516c212024-08-14 13:22:41 -05002333 std::string id = redfish::sensor_utils::getSensorId(sensorName, type);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002334
Ed Tanous14766872022-03-15 10:44:42 -07002335 nlohmann::json::object_t member;
Ed Tanousef4c65b2023-04-24 15:28:50 -07002336 member["@odata.id"] = boost::urls::format(
2337 "/redfish/v1/Chassis/{}/{}/{}", chassisId, chassisSubNode, id);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002338
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002339 entriesArray.emplace_back(std::move(member));
Nan Zhoubacb2162022-04-06 11:28:32 -07002340 }
2341
Ed Tanousc1d019a2022-08-06 09:36:06 -07002342 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Ed Tanous62598e32023-07-17 17:06:25 -07002343 BMCWEB_LOG_DEBUG("getChassisCallback exit");
Nan Zhoubacb2162022-04-06 11:28:32 -07002344}
Nan Zhoue6bd8462022-06-01 04:35:35 +00002345
Ed Tanousac106bf2023-06-07 09:24:59 -07002346inline void handleSensorCollectionGet(
2347 App& app, const crow::Request& req,
2348 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2349 const std::string& chassisId)
Nan Zhoude167a62022-06-01 04:47:45 +00002350{
2351 query_param::QueryCapabilities capabilities = {
2352 .canDelegateExpandLevel = 1,
2353 };
2354 query_param::Query delegatedQuery;
Ed Tanousac106bf2023-06-07 09:24:59 -07002355 if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
Nan Zhoude167a62022-06-01 04:47:45 +00002356 delegatedQuery, capabilities))
2357 {
2358 return;
2359 }
2360
2361 if (delegatedQuery.expandType != query_param::ExpandType::None)
2362 {
2363 // we perform efficient expand.
Ed Tanousac106bf2023-06-07 09:24:59 -07002364 auto sensorsAsyncResp = std::make_shared<SensorsAsyncResp>(
2365 asyncResp, chassisId, sensors::dbus::sensorPaths,
Janet Adkins0c728b42024-08-29 11:09:10 -05002366 sensors::sensorsNodeStr,
Nan Zhoude167a62022-06-01 04:47:45 +00002367 /*efficientExpand=*/true);
Ed Tanousac106bf2023-06-07 09:24:59 -07002368 getChassisData(sensorsAsyncResp);
Nan Zhoude167a62022-06-01 04:47:45 +00002369
Ed Tanous62598e32023-07-17 17:06:25 -07002370 BMCWEB_LOG_DEBUG(
2371 "SensorCollection doGet exit via efficient expand handler");
Nan Zhoude167a62022-06-01 04:47:45 +00002372 return;
Ed Tanous0bad3202022-06-02 13:53:59 -07002373 }
Nan Zhoude167a62022-06-01 04:47:45 +00002374
Nan Zhoude167a62022-06-01 04:47:45 +00002375 // We get all sensors as hyperlinkes in the chassis (this
2376 // implies we reply on the default query parameters handler)
Janet Adkins0c728b42024-08-29 11:09:10 -05002377 getChassis(asyncResp, chassisId, sensors::sensorsNodeStr, dbus::sensorPaths,
Ed Tanousac106bf2023-06-07 09:24:59 -07002378 std::bind_front(sensors::getChassisCallback, asyncResp,
Janet Adkins0c728b42024-08-29 11:09:10 -05002379 chassisId, sensors::sensorsNodeStr));
Ed Tanousc1d019a2022-08-06 09:36:06 -07002380}
Ed Tanous7f1cc262022-08-09 13:33:57 -07002381
Ed Tanousc1d019a2022-08-06 09:36:06 -07002382inline void
2383 getSensorFromDbus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2384 const std::string& sensorPath,
2385 const ::dbus::utility::MapperGetObject& mapperResponse)
2386{
2387 if (mapperResponse.size() != 1)
2388 {
2389 messages::internalError(asyncResp->res);
2390 return;
2391 }
2392 const auto& valueIface = *mapperResponse.begin();
2393 const std::string& connectionName = valueIface.first;
Ed Tanous62598e32023-07-17 17:06:25 -07002394 BMCWEB_LOG_DEBUG("Looking up {}", connectionName);
2395 BMCWEB_LOG_DEBUG("Path {}", sensorPath);
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +02002396
Ed Tanousdeae6a72024-11-11 21:58:57 -08002397 ::dbus::utility::getAllProperties(
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +02002398 *crow::connections::systemBus, connectionName, sensorPath, "",
Ed Tanousc1d019a2022-08-06 09:36:06 -07002399 [asyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002400 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002401 const ::dbus::utility::DBusPropertiesMap& valuesDict) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002402 if (ec)
2403 {
2404 messages::internalError(asyncResp->res);
2405 return;
2406 }
2407 sdbusplus::message::object_path path(sensorPath);
2408 std::string name = path.filename();
2409 path = path.parent_path();
2410 std::string type = path.filename();
Janet Adkinsc9563602024-08-28 11:37:46 -05002411 sensor_utils::objectPropertiesToJson(
Janet Adkins0c728b42024-08-29 11:09:10 -05002412 name, type, sensor_utils::ChassisSubNode::sensorsNode,
2413 valuesDict, asyncResp->res.jsonValue, nullptr);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002414 });
Nan Zhoude167a62022-06-01 04:47:45 +00002415}
2416
Nan Zhoue6bd8462022-06-01 04:35:35 +00002417inline void handleSensorGet(App& app, const crow::Request& req,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002418 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous677bb752022-09-15 10:52:19 -07002419 const std::string& chassisId,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002420 const std::string& sensorId)
Nan Zhoue6bd8462022-06-01 04:35:35 +00002421{
Ed Tanousc1d019a2022-08-06 09:36:06 -07002422 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Nan Zhoue6bd8462022-06-01 04:35:35 +00002423 {
2424 return;
2425 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002426 std::pair<std::string, std::string> nameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002427 redfish::sensor_utils::splitSensorNameAndType(sensorId);
Ed Tanousc71d6122022-11-29 14:10:32 -08002428 if (nameType.first.empty() || nameType.second.empty())
Ed Tanousc1d019a2022-08-06 09:36:06 -07002429 {
2430 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2431 return;
2432 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002433
Ed Tanousef4c65b2023-04-24 15:28:50 -07002434 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2435 "/redfish/v1/Chassis/{}/Sensors/{}", chassisId, sensorId);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002436
Ed Tanous62598e32023-07-17 17:06:25 -07002437 BMCWEB_LOG_DEBUG("Sensor doGet enter");
Nan Zhoue6bd8462022-06-01 04:35:35 +00002438
George Liu2b731192023-01-11 16:27:13 +08002439 constexpr std::array<std::string_view, 1> interfaces = {
Nan Zhoue6bd8462022-06-01 04:35:35 +00002440 "xyz.openbmc_project.Sensor.Value"};
Ed Tanousc71d6122022-11-29 14:10:32 -08002441 std::string sensorPath = "/xyz/openbmc_project/sensors/" + nameType.first +
2442 '/' + nameType.second;
Nan Zhoue6bd8462022-06-01 04:35:35 +00002443 // Get a list of all of the sensors that implement Sensor.Value
2444 // and get the path and service name associated with the sensor
George Liu2b731192023-01-11 16:27:13 +08002445 ::dbus::utility::getDbusObject(
2446 sensorPath, interfaces,
Myung Baeaec0ec32023-05-31 15:10:01 -05002447 [asyncResp, sensorId,
George Liu2b731192023-01-11 16:27:13 +08002448 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002449 const ::dbus::utility::MapperGetObject& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002450 BMCWEB_LOG_DEBUG("respHandler1 enter");
2451 if (ec == boost::system::errc::io_error)
2452 {
2453 BMCWEB_LOG_WARNING("Sensor not found from getSensorPaths");
2454 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2455 return;
2456 }
2457 if (ec)
2458 {
2459 messages::internalError(asyncResp->res);
2460 BMCWEB_LOG_ERROR(
2461 "Sensor getSensorPaths resp_handler: Dbus error {}", ec);
2462 return;
2463 }
2464 getSensorFromDbus(asyncResp, sensorPath, subtree);
2465 BMCWEB_LOG_DEBUG("respHandler1 exit");
2466 });
Nan Zhoue6bd8462022-06-01 04:35:35 +00002467}
2468
Nan Zhoubacb2162022-04-06 11:28:32 -07002469} // namespace sensors
2470
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002471inline void requestRoutesSensorCollection(App& app)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002472{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002473 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
Ed Tanoused398212021-06-09 17:05:54 -07002474 .privileges(redfish::privileges::getSensorCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002475 .methods(boost::beast::http::verb::get)(
Nan Zhoude167a62022-06-01 04:47:45 +00002476 std::bind_front(sensors::handleSensorCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002477}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002478
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002479inline void requestRoutesSensor(App& app)
2480{
2481 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002482 .privileges(redfish::privileges::getSensor)
Ed Tanous002d39b2022-05-31 08:59:27 -07002483 .methods(boost::beast::http::verb::get)(
Nan Zhoue6bd8462022-06-01 04:35:35 +00002484 std::bind_front(sensors::handleSensorGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002485}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002486
Ed Tanous1abe55e2018-09-05 08:30:59 -07002487} // namespace redfish