blob: 89c84e1f569744d54c3df43f43ffc54e3b3261c7 [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
George Liua7210022022-10-05 15:44:11 +08003#pragma once
4
5#include "app.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -08006#include "async_resp.hpp"
George Liua7210022022-10-05 15:44:11 +08007#include "dbus_utility.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -08008#include "error_messages.hpp"
Ed Tanous539d8c62024-06-19 14:38:27 -07009#include "generated/enums/resource.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080010#include "http_request.hpp"
Myung Bae7066dc52024-08-20 11:01:57 -050011#include "led.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080012#include "logging.hpp"
George Liua7210022022-10-05 15:44:11 +080013#include "query.hpp"
14#include "registries/privilege_registry.hpp"
15#include "utils/chassis_utils.hpp"
George Liu2b45fb32022-10-05 17:00:00 +080016#include "utils/dbus_utils.hpp"
Myung Bae7066dc52024-08-20 11:01:57 -050017#include "utils/json_utils.hpp"
Hieu Huynhb5190062024-07-11 03:47:21 +000018#include "utils/time_utils.hpp"
George Liua7210022022-10-05 15:44:11 +080019
Ed Tanousd7857202025-01-28 15:32:26 -080020#include <asm-generic/errno.h>
21
22#include <boost/beast/http/field.hpp>
23#include <boost/beast/http/verb.hpp>
George Liu34dfcb92022-10-05 16:47:44 +080024#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070025#include <boost/url/format.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080026#include <nlohmann/json.hpp>
27#include <sdbusplus/unpack_properties.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070028
Ed Tanousd7857202025-01-28 15:32:26 -080029#include <array>
30#include <cstdint>
31#include <functional>
George Liua7210022022-10-05 15:44:11 +080032#include <memory>
33#include <optional>
34#include <string>
Ed Tanousd7857202025-01-28 15:32:26 -080035#include <string_view>
36#include <utility>
George Liua7210022022-10-05 15:44:11 +080037
38namespace redfish
39{
40
Lakshmi Yadlapati788fe6c2023-06-21 14:39:08 -050041static constexpr std::array<std::string_view, 1> powerSupplyInterface = {
42 "xyz.openbmc_project.Inventory.Item.PowerSupply"};
43
44inline void updatePowerSupplyList(
45 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
46 const std::string& chassisId,
47 const dbus::utility::MapperGetSubTreePathsResponse& powerSupplyPaths)
George Liua7210022022-10-05 15:44:11 +080048{
George Liu00ef5dc2022-10-05 16:27:52 +080049 nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"];
Lakshmi Yadlapati788fe6c2023-06-21 14:39:08 -050050 for (const std::string& powerSupplyPath : powerSupplyPaths)
51 {
52 std::string powerSupplyName =
53 sdbusplus::message::object_path(powerSupplyPath).filename();
54 if (powerSupplyName.empty())
55 {
56 continue;
57 }
58
59 nlohmann::json item = nlohmann::json::object();
60 item["@odata.id"] = boost::urls::format(
61 "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
62 powerSupplyName);
63
64 powerSupplyList.emplace_back(std::move(item));
65 }
George Liu00ef5dc2022-10-05 16:27:52 +080066 asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size();
George Liua7210022022-10-05 15:44:11 +080067}
68
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -050069inline void doPowerSupplyCollection(
70 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
71 const std::string& chassisId, const boost::system::error_code& ec,
72 const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths)
George Liua7210022022-10-05 15:44:11 +080073{
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -050074 if (ec)
George Liua7210022022-10-05 15:44:11 +080075 {
Myung Bae193582b2025-03-31 07:21:31 -050076 if (ec.value() == boost::system::errc::io_error)
77 {
78 BMCWEB_LOG_WARNING("Chassis not found");
79 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
80 return;
81 }
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -050082 if (ec.value() != EBADR)
83 {
84 BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
85 messages::internalError(asyncResp->res);
86 }
George Liua7210022022-10-05 15:44:11 +080087 return;
88 }
George Liua7210022022-10-05 15:44:11 +080089 asyncResp->res.addHeader(
90 boost::beast::http::field::link,
91 "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
92 asyncResp->res.jsonValue["@odata.type"] =
93 "#PowerSupplyCollection.PowerSupplyCollection";
94 asyncResp->res.jsonValue["Name"] = "Power Supply Collection";
Ed Tanousef4c65b2023-04-24 15:28:50 -070095 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
96 "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId);
George Liua7210022022-10-05 15:44:11 +080097 asyncResp->res.jsonValue["Description"] =
98 "The collection of PowerSupply resource instances.";
George Liu7a2bb2c2023-04-11 10:44:33 +080099 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
100 asyncResp->res.jsonValue["Members@odata.count"] = 0;
George Liua7210022022-10-05 15:44:11 +0800101
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500102 updatePowerSupplyList(asyncResp, chassisId, subtreePaths);
George Liua7210022022-10-05 15:44:11 +0800103}
104
105inline void handlePowerSupplyCollectionHead(
106 App& app, const crow::Request& req,
107 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
108 const std::string& chassisId)
109{
110 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
111 {
112 return;
113 }
114
115 redfish::chassis_utils::getValidChassisPath(
116 asyncResp, chassisId,
117 [asyncResp,
118 chassisId](const std::optional<std::string>& validChassisPath) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400119 if (!validChassisPath)
120 {
Myung Bae193582b2025-03-31 07:21:31 -0500121 BMCWEB_LOG_WARNING("Chassis not found");
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400122 messages::resourceNotFound(asyncResp->res, "Chassis",
123 chassisId);
124 return;
125 }
126 asyncResp->res.addHeader(
127 boost::beast::http::field::link,
128 "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
129 });
George Liua7210022022-10-05 15:44:11 +0800130}
131
132inline void handlePowerSupplyCollectionGet(
133 App& app, const crow::Request& req,
134 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
135 const std::string& chassisId)
136{
137 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
138 {
139 return;
140 }
141
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500142 const std::string reqpath = "/xyz/openbmc_project/inventory";
143
144 dbus::utility::getAssociatedSubTreePathsById(
Myung Bae3f95a272024-03-13 07:32:02 -0700145 chassisId, reqpath, chassisInterfaces, "powered_by",
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500146 powerSupplyInterface,
147 [asyncResp, chassisId](
148 const boost::system::error_code& ec,
149 const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
150 doPowerSupplyCollection(asyncResp, chassisId, ec, subtreePaths);
151 });
George Liua7210022022-10-05 15:44:11 +0800152}
153
154inline void requestRoutesPowerSupplyCollection(App& app)
155{
156 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
157 .privileges(redfish::privileges::headPowerSupplyCollection)
158 .methods(boost::beast::http::verb::head)(
159 std::bind_front(handlePowerSupplyCollectionHead, std::ref(app)));
160
161 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
162 .privileges(redfish::privileges::getPowerSupplyCollection)
163 .methods(boost::beast::http::verb::get)(
164 std::bind_front(handlePowerSupplyCollectionGet, std::ref(app)));
165}
166
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500167inline void afterGetValidPowerSupplyPath(
168 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
169 const std::string& powerSupplyId, const boost::system::error_code& ec,
170 const dbus::utility::MapperGetSubTreeResponse& subtree,
171 const std::function<void(const std::string& powerSupplyPath,
172 const std::string& service)>& callback)
George Liu00ef5dc2022-10-05 16:27:52 +0800173{
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500174 if (ec)
175 {
Myung Bae193582b2025-03-31 07:21:31 -0500176 if (ec.value() == boost::system::errc::io_error)
177 {
178 // Not found
179 callback(std::string(), std::string());
180 return;
181 }
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500182 if (ec.value() != EBADR)
183 {
184 BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
185 messages::internalError(asyncResp->res);
Myung Bae193582b2025-03-31 07:21:31 -0500186 return;
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500187 }
Myung Bae193582b2025-03-31 07:21:31 -0500188 callback(std::string(), std::string());
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500189 return;
190 }
191 for (const auto& [objectPath, service] : subtree)
192 {
193 sdbusplus::message::object_path path(objectPath);
Myung Baed8e2b612024-10-08 12:19:19 -0500194 if (path.filename() == powerSupplyId)
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500195 {
196 callback(path, service.begin()->first);
197 return;
198 }
199 }
George Liu00ef5dc2022-10-05 16:27:52 +0800200
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500201 BMCWEB_LOG_WARNING("Power supply not found: {}", powerSupplyId);
202 messages::resourceNotFound(asyncResp->res, "PowerSupplies", powerSupplyId);
George Liu00ef5dc2022-10-05 16:27:52 +0800203}
204
George Liu34dfcb92022-10-05 16:47:44 +0800205inline void getValidPowerSupplyPath(
206 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500207 const std::string& chassisId, const std::string& powerSupplyId,
208 std::function<void(const std::string& powerSupplyPath,
209 const std::string& service)>&& callback)
George Liu00ef5dc2022-10-05 16:27:52 +0800210{
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500211 const std::string reqpath = "/xyz/openbmc_project/inventory";
212
213 dbus::utility::getAssociatedSubTreeById(
Myung Bae3f95a272024-03-13 07:32:02 -0700214 chassisId, reqpath, chassisInterfaces, "powered_by",
Lakshmi Yadlapati788fe6c2023-06-21 14:39:08 -0500215 powerSupplyInterface,
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500216 [asyncResp, chassisId, powerSupplyId, callback{std::move(callback)}](
Lakshmi Yadlapati788fe6c2023-06-21 14:39:08 -0500217 const boost::system::error_code& ec,
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500218 const dbus::utility::MapperGetSubTreeResponse& subtree) {
219 afterGetValidPowerSupplyPath(asyncResp, powerSupplyId, ec, subtree,
220 callback);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400221 });
George Liu00ef5dc2022-10-05 16:27:52 +0800222}
223
Patrick Williams504af5a2025-02-03 14:29:03 -0500224inline void getPowerSupplyState(
225 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
226 const std::string& service, const std::string& path)
George Liu34dfcb92022-10-05 16:47:44 +0800227{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800228 dbus::utility::getProperty<bool>(
229 service, path, "xyz.openbmc_project.Inventory.Item", "Present",
George Liu34dfcb92022-10-05 16:47:44 +0800230 [asyncResp](const boost::system::error_code& ec, const bool value) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400231 if (ec)
George Liu34dfcb92022-10-05 16:47:44 +0800232 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400233 if (ec.value() != EBADR)
234 {
235 BMCWEB_LOG_ERROR("DBUS response error for State {}",
236 ec.value());
237 messages::internalError(asyncResp->res);
238 }
239 return;
George Liu34dfcb92022-10-05 16:47:44 +0800240 }
George Liu34dfcb92022-10-05 16:47:44 +0800241
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400242 if (!value)
243 {
244 asyncResp->res.jsonValue["Status"]["State"] =
245 resource::State::Absent;
246 }
247 });
George Liu34dfcb92022-10-05 16:47:44 +0800248}
249
Patrick Williams504af5a2025-02-03 14:29:03 -0500250inline void getPowerSupplyHealth(
251 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
252 const std::string& service, const std::string& path)
George Liu34dfcb92022-10-05 16:47:44 +0800253{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800254 dbus::utility::getProperty<bool>(
255 service, path, "xyz.openbmc_project.State.Decorator.OperationalStatus",
256 "Functional",
George Liu34dfcb92022-10-05 16:47:44 +0800257 [asyncResp](const boost::system::error_code& ec, const bool value) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400258 if (ec)
George Liu34dfcb92022-10-05 16:47:44 +0800259 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400260 if (ec.value() != EBADR)
261 {
262 BMCWEB_LOG_ERROR("DBUS response error for Health {}",
263 ec.value());
264 messages::internalError(asyncResp->res);
265 }
266 return;
George Liu34dfcb92022-10-05 16:47:44 +0800267 }
George Liu34dfcb92022-10-05 16:47:44 +0800268
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400269 if (!value)
270 {
271 asyncResp->res.jsonValue["Status"]["Health"] =
272 resource::Health::Critical;
273 }
274 });
George Liu34dfcb92022-10-05 16:47:44 +0800275}
276
Patrick Williams504af5a2025-02-03 14:29:03 -0500277inline void getPowerSupplyAsset(
278 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
279 const std::string& service, const std::string& path)
George Liu2b45fb32022-10-05 17:00:00 +0800280{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800281 dbus::utility::getAllProperties(
282 service, path, "xyz.openbmc_project.Inventory.Decorator.Asset",
George Liu2b45fb32022-10-05 17:00:00 +0800283 [asyncResp](const boost::system::error_code& ec,
284 const dbus::utility::DBusPropertiesMap& propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400285 if (ec)
George Liu2b45fb32022-10-05 17:00:00 +0800286 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400287 if (ec.value() != EBADR)
288 {
289 BMCWEB_LOG_ERROR("DBUS response error for Asset {}",
290 ec.value());
291 messages::internalError(asyncResp->res);
292 }
293 return;
George Liu2b45fb32022-10-05 17:00:00 +0800294 }
George Liu2b45fb32022-10-05 17:00:00 +0800295
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400296 const std::string* partNumber = nullptr;
297 const std::string* serialNumber = nullptr;
298 const std::string* manufacturer = nullptr;
299 const std::string* model = nullptr;
300 const std::string* sparePartNumber = nullptr;
Hieu Huynhb5190062024-07-11 03:47:21 +0000301 const std::string* buildDate = nullptr;
George Liu2b45fb32022-10-05 17:00:00 +0800302
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400303 const bool success = sdbusplus::unpackPropertiesNoThrow(
304 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
305 partNumber, "SerialNumber", serialNumber, "Manufacturer",
306 manufacturer, "Model", model, "SparePartNumber",
Hieu Huynhb5190062024-07-11 03:47:21 +0000307 sparePartNumber, "BuildDate", buildDate);
George Liu2b45fb32022-10-05 17:00:00 +0800308
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400309 if (!success)
310 {
311 messages::internalError(asyncResp->res);
312 return;
313 }
George Liu2b45fb32022-10-05 17:00:00 +0800314
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400315 if (partNumber != nullptr)
316 {
317 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
318 }
George Liu2b45fb32022-10-05 17:00:00 +0800319
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400320 if (serialNumber != nullptr)
321 {
322 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
323 }
George Liu2b45fb32022-10-05 17:00:00 +0800324
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400325 if (manufacturer != nullptr)
326 {
327 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
328 }
George Liu2b45fb32022-10-05 17:00:00 +0800329
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400330 if (model != nullptr)
331 {
332 asyncResp->res.jsonValue["Model"] = *model;
333 }
George Liu2b45fb32022-10-05 17:00:00 +0800334
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400335 // SparePartNumber is optional on D-Bus so skip if it is empty
336 if (sparePartNumber != nullptr && !sparePartNumber->empty())
337 {
338 asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
339 }
Hieu Huynhb5190062024-07-11 03:47:21 +0000340
341 if (buildDate != nullptr)
342 {
343 time_utils::productionDateReport(asyncResp->res, *buildDate);
344 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400345 });
George Liu2b45fb32022-10-05 17:00:00 +0800346}
347
George Liua0dba872022-10-05 17:03:20 +0800348inline void getPowerSupplyFirmwareVersion(
349 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
350 const std::string& service, const std::string& path)
351{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800352 dbus::utility::getProperty<std::string>(
353 service, path, "xyz.openbmc_project.Software.Version", "Version",
George Liua0dba872022-10-05 17:03:20 +0800354 [asyncResp](const boost::system::error_code& ec,
355 const std::string& value) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400356 if (ec)
George Liua0dba872022-10-05 17:03:20 +0800357 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400358 if (ec.value() != EBADR)
359 {
360 BMCWEB_LOG_ERROR(
361 "DBUS response error for FirmwareVersion {}",
362 ec.value());
363 messages::internalError(asyncResp->res);
364 }
365 return;
George Liua0dba872022-10-05 17:03:20 +0800366 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400367 asyncResp->res.jsonValue["FirmwareVersion"] = value;
368 });
George Liua0dba872022-10-05 17:03:20 +0800369}
370
Patrick Williams504af5a2025-02-03 14:29:03 -0500371inline void getPowerSupplyLocation(
372 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
373 const std::string& service, const std::string& path)
George Liu44845e52022-10-05 17:09:21 +0800374{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800375 dbus::utility::getProperty<std::string>(
376 service, path, "xyz.openbmc_project.Inventory.Decorator.LocationCode",
377 "LocationCode",
George Liu44845e52022-10-05 17:09:21 +0800378 [asyncResp](const boost::system::error_code& ec,
379 const std::string& value) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400380 if (ec)
George Liu44845e52022-10-05 17:09:21 +0800381 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400382 if (ec.value() != EBADR)
383 {
384 BMCWEB_LOG_ERROR("DBUS response error for Location {}",
385 ec.value());
386 messages::internalError(asyncResp->res);
387 }
388 return;
George Liu44845e52022-10-05 17:09:21 +0800389 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400390 asyncResp->res
391 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = value;
392 });
George Liu44845e52022-10-05 17:09:21 +0800393}
394
George Liuddceee02022-10-06 08:57:11 +0800395inline void handleGetEfficiencyResponse(
396 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
397 const boost::system::error_code& ec, uint32_t value)
398{
399 if (ec)
400 {
401 if (ec.value() != EBADR)
402 {
Ed Tanous62598e32023-07-17 17:06:25 -0700403 BMCWEB_LOG_ERROR("DBUS response error for DeratingFactor {}",
404 ec.value());
George Liuddceee02022-10-06 08:57:11 +0800405 messages::internalError(asyncResp->res);
406 }
407 return;
408 }
409 // The PDI default value is 0, if it hasn't been set leave off
410 if (value == 0)
411 {
412 return;
413 }
414
415 nlohmann::json::array_t efficiencyRatings;
416 nlohmann::json::object_t efficiencyPercent;
417 efficiencyPercent["EfficiencyPercent"] = value;
418 efficiencyRatings.emplace_back(std::move(efficiencyPercent));
419 asyncResp->res.jsonValue["EfficiencyRatings"] =
420 std::move(efficiencyRatings);
421}
422
423inline void handlePowerSupplyAttributesSubTreeResponse(
424 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
425 const boost::system::error_code& ec,
426 const dbus::utility::MapperGetSubTreeResponse& subtree)
427{
428 if (ec)
429 {
430 if (ec.value() != EBADR)
431 {
Ed Tanous62598e32023-07-17 17:06:25 -0700432 BMCWEB_LOG_ERROR("DBUS response error for EfficiencyPercent {}",
433 ec.value());
George Liuddceee02022-10-06 08:57:11 +0800434 messages::internalError(asyncResp->res);
435 }
436 return;
437 }
438
439 if (subtree.empty())
440 {
Ed Tanous62598e32023-07-17 17:06:25 -0700441 BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
George Liuddceee02022-10-06 08:57:11 +0800442 return;
443 }
444
445 if (subtree.size() != 1)
446 {
Ed Tanous62598e32023-07-17 17:06:25 -0700447 BMCWEB_LOG_ERROR(
448 "Unexpected number of paths returned by getSubTree: {}",
449 subtree.size());
George Liuddceee02022-10-06 08:57:11 +0800450 messages::internalError(asyncResp->res);
451 return;
452 }
453
454 const auto& [path, serviceMap] = *subtree.begin();
455 const auto& [service, interfaces] = *serviceMap.begin();
Ed Tanousdeae6a72024-11-11 21:58:57 -0800456 dbus::utility::getProperty<uint32_t>(
457 service, path, "xyz.openbmc_project.Control.PowerSupplyAttributes",
458 "DeratingFactor",
George Liuddceee02022-10-06 08:57:11 +0800459 [asyncResp](const boost::system::error_code& ec1, uint32_t value) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400460 handleGetEfficiencyResponse(asyncResp, ec1, value);
461 });
George Liuddceee02022-10-06 08:57:11 +0800462}
463
Patrick Williams504af5a2025-02-03 14:29:03 -0500464inline void getEfficiencyPercent(
465 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
George Liuddceee02022-10-06 08:57:11 +0800466{
467 constexpr std::array<std::string_view, 1> efficiencyIntf = {
468 "xyz.openbmc_project.Control.PowerSupplyAttributes"};
469
470 dbus::utility::getSubTree(
471 "/xyz/openbmc_project", 0, efficiencyIntf,
472 [asyncResp](const boost::system::error_code& ec,
473 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400474 handlePowerSupplyAttributesSubTreeResponse(asyncResp, ec, subtree);
475 });
George Liuddceee02022-10-06 08:57:11 +0800476}
477
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400478inline void doPowerSupplyGet(
479 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
480 const std::string& chassisId, const std::string& powerSupplyId,
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500481 const std::string& powerSupplyPath, const std::string& service)
George Liu00ef5dc2022-10-05 16:27:52 +0800482{
Myung Bae193582b2025-03-31 07:21:31 -0500483 if (powerSupplyPath.empty() || service.empty())
484 {
485 BMCWEB_LOG_WARNING("PowerSupply not found");
486 messages::resourceNotFound(asyncResp->res, "PowerSupply",
487 powerSupplyId);
488 return;
489 }
490
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500491 asyncResp->res.addHeader(
492 boost::beast::http::field::link,
493 "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
494 asyncResp->res.jsonValue["@odata.type"] = "#PowerSupply.v1_5_0.PowerSupply";
495 asyncResp->res.jsonValue["Name"] = "Power Supply";
496 asyncResp->res.jsonValue["Id"] = powerSupplyId;
497 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
498 "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
499 powerSupplyId);
George Liu00ef5dc2022-10-05 16:27:52 +0800500
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500501 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
502 asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
George Liu34dfcb92022-10-05 16:47:44 +0800503
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500504 getPowerSupplyState(asyncResp, service, powerSupplyPath);
505 getPowerSupplyHealth(asyncResp, service, powerSupplyPath);
506 getPowerSupplyAsset(asyncResp, service, powerSupplyPath);
507 getPowerSupplyFirmwareVersion(asyncResp, service, powerSupplyPath);
508 getPowerSupplyLocation(asyncResp, service, powerSupplyPath);
509 getEfficiencyPercent(asyncResp);
Myung Bae7066dc52024-08-20 11:01:57 -0500510 getLocationIndicatorActive(asyncResp, powerSupplyPath);
George Liu00ef5dc2022-10-05 16:27:52 +0800511}
512
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400513inline void handlePowerSupplyHead(
514 App& app, const crow::Request& req,
515 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
516 const std::string& chassisId, const std::string& powerSupplyId)
George Liu00ef5dc2022-10-05 16:27:52 +0800517{
518 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
519 {
520 return;
521 }
522
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500523 // Get the correct Path and Service that match the input parameters
524 getValidPowerSupplyPath(
525 asyncResp, chassisId, powerSupplyId,
Myung Bae193582b2025-03-31 07:21:31 -0500526 [asyncResp, powerSupplyId](const std::string& powerSupplyPath,
527 const std::string& service) {
528 if (powerSupplyPath.empty() || service.empty())
529 {
530 BMCWEB_LOG_WARNING("PowerSupply not found");
531 messages::resourceNotFound(asyncResp->res, "PowerSupply",
532 powerSupplyId);
533 return;
534 }
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500535 asyncResp->res.addHeader(
536 boost::beast::http::field::link,
537 "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
George Liu00ef5dc2022-10-05 16:27:52 +0800538 });
George Liu00ef5dc2022-10-05 16:27:52 +0800539}
540
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400541inline void handlePowerSupplyGet(
542 App& app, const crow::Request& req,
543 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
544 const std::string& chassisId, const std::string& powerSupplyId)
George Liu00ef5dc2022-10-05 16:27:52 +0800545{
546 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
547 {
548 return;
549 }
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500550 getValidPowerSupplyPath(
551 asyncResp, chassisId, powerSupplyId,
George Liu00ef5dc2022-10-05 16:27:52 +0800552 std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId));
553}
554
Myung Bae7066dc52024-08-20 11:01:57 -0500555inline void doPatchPowerSupply(
556 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
557 const bool locationIndicatorActive, const std::string& powerSupplyPath,
558 const std::string& /*service*/)
559{
560 setLocationIndicatorActive(asyncResp, powerSupplyPath,
561 locationIndicatorActive);
562}
563
564inline void handlePowerSupplyPatch(
565 App& app, const crow::Request& req,
566 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
567 const std::string& chassisId, const std::string& powerSupplyId)
568{
569 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
570 {
571 return;
572 }
573
574 std::optional<bool> locationIndicatorActive;
575 if (!json_util::readJsonPatch( //
576 req, asyncResp->res, //
577 "LocationIndicatorActive", locationIndicatorActive //
578 ))
579 {
580 return;
581 }
582
583 if (locationIndicatorActive)
584 {
585 // Get the correct power supply Path that match the input parameters
586 getValidPowerSupplyPath(asyncResp, chassisId, powerSupplyId,
587 std::bind_front(doPatchPowerSupply, asyncResp,
588 *locationIndicatorActive));
589 }
590}
591
George Liu00ef5dc2022-10-05 16:27:52 +0800592inline void requestRoutesPowerSupply(App& app)
593{
594 BMCWEB_ROUTE(
595 app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
596 .privileges(redfish::privileges::headPowerSupply)
597 .methods(boost::beast::http::verb::head)(
598 std::bind_front(handlePowerSupplyHead, std::ref(app)));
599
600 BMCWEB_ROUTE(
601 app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
602 .privileges(redfish::privileges::getPowerSupply)
603 .methods(boost::beast::http::verb::get)(
604 std::bind_front(handlePowerSupplyGet, std::ref(app)));
Myung Bae7066dc52024-08-20 11:01:57 -0500605
606 BMCWEB_ROUTE(
607 app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
608 .privileges(redfish::privileges::patchPowerSupply)
609 .methods(boost::beast::http::verb::patch)(
610 std::bind_front(handlePowerSupplyPatch, std::ref(app)));
George Liu00ef5dc2022-10-05 16:27:52 +0800611}
612
George Liua7210022022-10-05 15:44:11 +0800613} // namespace redfish