xref: /openbmc/bmcweb/features/redfish/lib/power_supply.hpp (revision d78572018fc2022091ff8b8eb5a7fef2172ba3d6)
140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3a7210020SGeorge Liu #pragma once
4a7210020SGeorge Liu 
5a7210020SGeorge Liu #include "app.hpp"
6*d7857201SEd Tanous #include "async_resp.hpp"
7a7210020SGeorge Liu #include "dbus_utility.hpp"
8*d7857201SEd Tanous #include "error_messages.hpp"
9539d8c6bSEd Tanous #include "generated/enums/resource.hpp"
10*d7857201SEd Tanous #include "http_request.hpp"
11*d7857201SEd Tanous #include "logging.hpp"
12a7210020SGeorge Liu #include "query.hpp"
13a7210020SGeorge Liu #include "registries/privilege_registry.hpp"
14a7210020SGeorge Liu #include "utils/chassis_utils.hpp"
152b45fb3bSGeorge Liu #include "utils/dbus_utils.hpp"
16b5190062SHieu Huynh #include "utils/time_utils.hpp"
17a7210020SGeorge Liu 
18*d7857201SEd Tanous #include <asm-generic/errno.h>
19*d7857201SEd Tanous 
20*d7857201SEd Tanous #include <boost/beast/http/field.hpp>
21*d7857201SEd Tanous #include <boost/beast/http/verb.hpp>
2234dfcb94SGeorge Liu #include <boost/system/error_code.hpp>
23ef4c65b7SEd Tanous #include <boost/url/format.hpp>
24*d7857201SEd Tanous #include <nlohmann/json.hpp>
25*d7857201SEd Tanous #include <sdbusplus/unpack_properties.hpp>
26ef4c65b7SEd Tanous 
27*d7857201SEd Tanous #include <array>
28*d7857201SEd Tanous #include <cstdint>
29*d7857201SEd Tanous #include <functional>
30a7210020SGeorge Liu #include <memory>
31a7210020SGeorge Liu #include <optional>
32a7210020SGeorge Liu #include <string>
33*d7857201SEd Tanous #include <string_view>
34*d7857201SEd Tanous #include <utility>
35a7210020SGeorge Liu 
36a7210020SGeorge Liu namespace redfish
37a7210020SGeorge Liu {
38a7210020SGeorge Liu 
39788fe6cfSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> powerSupplyInterface = {
40788fe6cfSLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PowerSupply"};
41788fe6cfSLakshmi Yadlapati 
42788fe6cfSLakshmi Yadlapati inline void updatePowerSupplyList(
43788fe6cfSLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4400ef5dc6SGeorge Liu     const std::string& chassisId,
45788fe6cfSLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& powerSupplyPaths)
46788fe6cfSLakshmi Yadlapati {
47788fe6cfSLakshmi Yadlapati     nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"];
48788fe6cfSLakshmi Yadlapati     for (const std::string& powerSupplyPath : powerSupplyPaths)
49a7210020SGeorge Liu     {
5000ef5dc6SGeorge Liu         std::string powerSupplyName =
5100ef5dc6SGeorge Liu             sdbusplus::message::object_path(powerSupplyPath).filename();
5200ef5dc6SGeorge Liu         if (powerSupplyName.empty())
5300ef5dc6SGeorge Liu         {
54788fe6cfSLakshmi Yadlapati             continue;
5500ef5dc6SGeorge Liu         }
5600ef5dc6SGeorge Liu 
5700ef5dc6SGeorge Liu         nlohmann::json item = nlohmann::json::object();
5800ef5dc6SGeorge Liu         item["@odata.id"] = boost::urls::format(
5900ef5dc6SGeorge Liu             "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
6000ef5dc6SGeorge Liu             powerSupplyName);
6100ef5dc6SGeorge Liu 
6200ef5dc6SGeorge Liu         powerSupplyList.emplace_back(std::move(item));
63788fe6cfSLakshmi Yadlapati     }
6400ef5dc6SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size();
65a7210020SGeorge Liu }
66a7210020SGeorge Liu 
673e42a329SLakshmi Yadlapati inline void doPowerSupplyCollection(
683e42a329SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
693e42a329SLakshmi Yadlapati     const std::string& chassisId, const boost::system::error_code& ec,
703e42a329SLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths)
71a7210020SGeorge Liu {
723e42a329SLakshmi Yadlapati     if (ec)
73a7210020SGeorge Liu     {
743e42a329SLakshmi Yadlapati         if (ec.value() != EBADR)
753e42a329SLakshmi Yadlapati         {
763e42a329SLakshmi Yadlapati             BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
773e42a329SLakshmi Yadlapati             messages::internalError(asyncResp->res);
783e42a329SLakshmi Yadlapati         }
79a7210020SGeorge Liu         return;
80a7210020SGeorge Liu     }
81a7210020SGeorge Liu     asyncResp->res.addHeader(
82a7210020SGeorge Liu         boost::beast::http::field::link,
83a7210020SGeorge Liu         "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
84a7210020SGeorge Liu     asyncResp->res.jsonValue["@odata.type"] =
85a7210020SGeorge Liu         "#PowerSupplyCollection.PowerSupplyCollection";
86a7210020SGeorge Liu     asyncResp->res.jsonValue["Name"] = "Power Supply Collection";
87ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
88ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId);
89a7210020SGeorge Liu     asyncResp->res.jsonValue["Description"] =
90a7210020SGeorge Liu         "The collection of PowerSupply resource instances.";
917a2bb2c9SGeorge Liu     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
927a2bb2c9SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = 0;
93a7210020SGeorge Liu 
94788fe6cfSLakshmi Yadlapati     updatePowerSupplyList(asyncResp, chassisId, subtreePaths);
95a7210020SGeorge Liu }
96a7210020SGeorge Liu 
97a7210020SGeorge Liu inline void handlePowerSupplyCollectionHead(
98a7210020SGeorge Liu     App& app, const crow::Request& req,
99a7210020SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
100a7210020SGeorge Liu     const std::string& chassisId)
101a7210020SGeorge Liu {
102a7210020SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
103a7210020SGeorge Liu     {
104a7210020SGeorge Liu         return;
105a7210020SGeorge Liu     }
106a7210020SGeorge Liu 
107a7210020SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
108a7210020SGeorge Liu         asyncResp, chassisId,
109a7210020SGeorge Liu         [asyncResp,
110a7210020SGeorge Liu          chassisId](const std::optional<std::string>& validChassisPath) {
111a7210020SGeorge Liu             if (!validChassisPath)
112a7210020SGeorge Liu             {
113bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res, "Chassis",
114bd79bce8SPatrick Williams                                            chassisId);
115a7210020SGeorge Liu                 return;
116a7210020SGeorge Liu             }
117a7210020SGeorge Liu             asyncResp->res.addHeader(
118a7210020SGeorge Liu                 boost::beast::http::field::link,
119a7210020SGeorge Liu                 "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
120a7210020SGeorge Liu         });
121a7210020SGeorge Liu }
122a7210020SGeorge Liu 
123a7210020SGeorge Liu inline void handlePowerSupplyCollectionGet(
124a7210020SGeorge Liu     App& app, const crow::Request& req,
125a7210020SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
126a7210020SGeorge Liu     const std::string& chassisId)
127a7210020SGeorge Liu {
128a7210020SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
129a7210020SGeorge Liu     {
130a7210020SGeorge Liu         return;
131a7210020SGeorge Liu     }
132a7210020SGeorge Liu 
1333e42a329SLakshmi Yadlapati     constexpr std::array<std::string_view, 2> chasisInterfaces = {
1343e42a329SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.Board",
1353e42a329SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.Chassis"};
1363e42a329SLakshmi Yadlapati     const std::string reqpath = "/xyz/openbmc_project/inventory";
1373e42a329SLakshmi Yadlapati 
1383e42a329SLakshmi Yadlapati     dbus::utility::getAssociatedSubTreePathsById(
1393e42a329SLakshmi Yadlapati         chassisId, reqpath, chasisInterfaces, "powered_by",
1403e42a329SLakshmi Yadlapati         powerSupplyInterface,
1413e42a329SLakshmi Yadlapati         [asyncResp, chassisId](
1423e42a329SLakshmi Yadlapati             const boost::system::error_code& ec,
1433e42a329SLakshmi Yadlapati             const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
1443e42a329SLakshmi Yadlapati             doPowerSupplyCollection(asyncResp, chassisId, ec, subtreePaths);
1453e42a329SLakshmi Yadlapati         });
146a7210020SGeorge Liu }
147a7210020SGeorge Liu 
148a7210020SGeorge Liu inline void requestRoutesPowerSupplyCollection(App& app)
149a7210020SGeorge Liu {
150a7210020SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
151a7210020SGeorge Liu         .privileges(redfish::privileges::headPowerSupplyCollection)
152a7210020SGeorge Liu         .methods(boost::beast::http::verb::head)(
153a7210020SGeorge Liu             std::bind_front(handlePowerSupplyCollectionHead, std::ref(app)));
154a7210020SGeorge Liu 
155a7210020SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
156a7210020SGeorge Liu         .privileges(redfish::privileges::getPowerSupplyCollection)
157a7210020SGeorge Liu         .methods(boost::beast::http::verb::get)(
158a7210020SGeorge Liu             std::bind_front(handlePowerSupplyCollectionGet, std::ref(app)));
159a7210020SGeorge Liu }
160a7210020SGeorge Liu 
1613e42a329SLakshmi Yadlapati inline void afterGetValidPowerSupplyPath(
16234dfcb94SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1633e42a329SLakshmi Yadlapati     const std::string& powerSupplyId, const boost::system::error_code& ec,
1643e42a329SLakshmi Yadlapati     const dbus::utility::MapperGetSubTreeResponse& subtree,
1653e42a329SLakshmi Yadlapati     const std::function<void(const std::string& powerSupplyPath,
1663e42a329SLakshmi Yadlapati                              const std::string& service)>& callback)
16700ef5dc6SGeorge Liu {
16800ef5dc6SGeorge Liu     if (ec)
16900ef5dc6SGeorge Liu     {
17000ef5dc6SGeorge Liu         if (ec.value() != EBADR)
17100ef5dc6SGeorge Liu         {
1723e42a329SLakshmi Yadlapati             BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
17300ef5dc6SGeorge Liu             messages::internalError(asyncResp->res);
1743e42a329SLakshmi Yadlapati         }
17500ef5dc6SGeorge Liu         return;
17600ef5dc6SGeorge Liu     }
1773e42a329SLakshmi Yadlapati     for (const auto& [objectPath, service] : subtree)
17800ef5dc6SGeorge Liu     {
1793e42a329SLakshmi Yadlapati         sdbusplus::message::object_path path(objectPath);
180d8e2b618SMyung Bae         if (path.filename() == powerSupplyId)
18100ef5dc6SGeorge Liu         {
1823e42a329SLakshmi Yadlapati             callback(path, service.begin()->first);
18300ef5dc6SGeorge Liu             return;
18400ef5dc6SGeorge Liu         }
18500ef5dc6SGeorge Liu     }
18600ef5dc6SGeorge Liu 
18762598e31SEd Tanous     BMCWEB_LOG_WARNING("Power supply not found: {}", powerSupplyId);
1883e42a329SLakshmi Yadlapati     messages::resourceNotFound(asyncResp->res, "PowerSupplies", powerSupplyId);
18900ef5dc6SGeorge Liu }
1903e42a329SLakshmi Yadlapati 
1913e42a329SLakshmi Yadlapati inline void getValidPowerSupplyPath(
1923e42a329SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1933e42a329SLakshmi Yadlapati     const std::string& chassisId, const std::string& powerSupplyId,
1943e42a329SLakshmi Yadlapati     std::function<void(const std::string& powerSupplyPath,
1953e42a329SLakshmi Yadlapati                        const std::string& service)>&& callback)
1963e42a329SLakshmi Yadlapati {
1973e42a329SLakshmi Yadlapati     constexpr std::array<std::string_view, 2> chasisInterfaces = {
1983e42a329SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.Board",
1993e42a329SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.Chassis"};
2003e42a329SLakshmi Yadlapati     const std::string reqpath = "/xyz/openbmc_project/inventory";
2013e42a329SLakshmi Yadlapati 
2023e42a329SLakshmi Yadlapati     dbus::utility::getAssociatedSubTreeById(
2033e42a329SLakshmi Yadlapati         chassisId, reqpath, chasisInterfaces, "powered_by",
2043e42a329SLakshmi Yadlapati         powerSupplyInterface,
2053e42a329SLakshmi Yadlapati         [asyncResp, chassisId, powerSupplyId, callback{std::move(callback)}](
2063e42a329SLakshmi Yadlapati             const boost::system::error_code& ec,
2073e42a329SLakshmi Yadlapati             const dbus::utility::MapperGetSubTreeResponse& subtree) {
2083e42a329SLakshmi Yadlapati             afterGetValidPowerSupplyPath(asyncResp, powerSupplyId, ec, subtree,
2093e42a329SLakshmi Yadlapati                                          callback);
21000ef5dc6SGeorge Liu         });
21100ef5dc6SGeorge Liu }
21200ef5dc6SGeorge Liu 
21300ef5dc6SGeorge Liu inline void
21434dfcb94SGeorge Liu     getPowerSupplyState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
21534dfcb94SGeorge Liu                         const std::string& service, const std::string& path)
21634dfcb94SGeorge Liu {
217deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
218deae6a78SEd Tanous         service, path, "xyz.openbmc_project.Inventory.Item", "Present",
21934dfcb94SGeorge Liu         [asyncResp](const boost::system::error_code& ec, const bool value) {
22034dfcb94SGeorge Liu             if (ec)
22134dfcb94SGeorge Liu             {
22234dfcb94SGeorge Liu                 if (ec.value() != EBADR)
22334dfcb94SGeorge Liu                 {
22462598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for State {}",
22562598e31SEd Tanous                                      ec.value());
22634dfcb94SGeorge Liu                     messages::internalError(asyncResp->res);
22734dfcb94SGeorge Liu                 }
22834dfcb94SGeorge Liu                 return;
22934dfcb94SGeorge Liu             }
23034dfcb94SGeorge Liu 
23134dfcb94SGeorge Liu             if (!value)
23234dfcb94SGeorge Liu             {
233539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
234539d8c6bSEd Tanous                     resource::State::Absent;
23534dfcb94SGeorge Liu             }
23634dfcb94SGeorge Liu         });
23734dfcb94SGeorge Liu }
23834dfcb94SGeorge Liu 
23934dfcb94SGeorge Liu inline void
24034dfcb94SGeorge Liu     getPowerSupplyHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
24134dfcb94SGeorge Liu                          const std::string& service, const std::string& path)
24234dfcb94SGeorge Liu {
243deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
244deae6a78SEd Tanous         service, path, "xyz.openbmc_project.State.Decorator.OperationalStatus",
245deae6a78SEd Tanous         "Functional",
24634dfcb94SGeorge Liu         [asyncResp](const boost::system::error_code& ec, const bool value) {
24734dfcb94SGeorge Liu             if (ec)
24834dfcb94SGeorge Liu             {
24934dfcb94SGeorge Liu                 if (ec.value() != EBADR)
25034dfcb94SGeorge Liu                 {
25162598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Health {}",
25262598e31SEd Tanous                                      ec.value());
25334dfcb94SGeorge Liu                     messages::internalError(asyncResp->res);
25434dfcb94SGeorge Liu                 }
25534dfcb94SGeorge Liu                 return;
25634dfcb94SGeorge Liu             }
25734dfcb94SGeorge Liu 
25834dfcb94SGeorge Liu             if (!value)
25934dfcb94SGeorge Liu             {
260539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["Health"] =
261539d8c6bSEd Tanous                     resource::Health::Critical;
26234dfcb94SGeorge Liu             }
26334dfcb94SGeorge Liu         });
26434dfcb94SGeorge Liu }
26534dfcb94SGeorge Liu 
26634dfcb94SGeorge Liu inline void
2672b45fb3bSGeorge Liu     getPowerSupplyAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2682b45fb3bSGeorge Liu                         const std::string& service, const std::string& path)
2692b45fb3bSGeorge Liu {
270deae6a78SEd Tanous     dbus::utility::getAllProperties(
271deae6a78SEd Tanous         service, path, "xyz.openbmc_project.Inventory.Decorator.Asset",
2722b45fb3bSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
2732b45fb3bSGeorge Liu                     const dbus::utility::DBusPropertiesMap& propertiesList) {
2742b45fb3bSGeorge Liu             if (ec)
2752b45fb3bSGeorge Liu             {
2762b45fb3bSGeorge Liu                 if (ec.value() != EBADR)
2772b45fb3bSGeorge Liu                 {
27862598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Asset {}",
27962598e31SEd Tanous                                      ec.value());
2802b45fb3bSGeorge Liu                     messages::internalError(asyncResp->res);
2812b45fb3bSGeorge Liu                 }
2822b45fb3bSGeorge Liu                 return;
2832b45fb3bSGeorge Liu             }
2842b45fb3bSGeorge Liu 
2852b45fb3bSGeorge Liu             const std::string* partNumber = nullptr;
2862b45fb3bSGeorge Liu             const std::string* serialNumber = nullptr;
2872b45fb3bSGeorge Liu             const std::string* manufacturer = nullptr;
2882b45fb3bSGeorge Liu             const std::string* model = nullptr;
2892b45fb3bSGeorge Liu             const std::string* sparePartNumber = nullptr;
290b5190062SHieu Huynh             const std::string* buildDate = nullptr;
2912b45fb3bSGeorge Liu 
2922b45fb3bSGeorge Liu             const bool success = sdbusplus::unpackPropertiesNoThrow(
2932b45fb3bSGeorge Liu                 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
2942b45fb3bSGeorge Liu                 partNumber, "SerialNumber", serialNumber, "Manufacturer",
295bd79bce8SPatrick Williams                 manufacturer, "Model", model, "SparePartNumber",
296b5190062SHieu Huynh                 sparePartNumber, "BuildDate", buildDate);
2972b45fb3bSGeorge Liu 
2982b45fb3bSGeorge Liu             if (!success)
2992b45fb3bSGeorge Liu             {
3002b45fb3bSGeorge Liu                 messages::internalError(asyncResp->res);
3012b45fb3bSGeorge Liu                 return;
3022b45fb3bSGeorge Liu             }
3032b45fb3bSGeorge Liu 
3042b45fb3bSGeorge Liu             if (partNumber != nullptr)
3052b45fb3bSGeorge Liu             {
3062b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
3072b45fb3bSGeorge Liu             }
3082b45fb3bSGeorge Liu 
3092b45fb3bSGeorge Liu             if (serialNumber != nullptr)
3102b45fb3bSGeorge Liu             {
3112b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
3122b45fb3bSGeorge Liu             }
3132b45fb3bSGeorge Liu 
3142b45fb3bSGeorge Liu             if (manufacturer != nullptr)
3152b45fb3bSGeorge Liu             {
3162b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
3172b45fb3bSGeorge Liu             }
3182b45fb3bSGeorge Liu 
3192b45fb3bSGeorge Liu             if (model != nullptr)
3202b45fb3bSGeorge Liu             {
3212b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["Model"] = *model;
3222b45fb3bSGeorge Liu             }
3232b45fb3bSGeorge Liu 
3242b45fb3bSGeorge Liu             // SparePartNumber is optional on D-Bus so skip if it is empty
3252b45fb3bSGeorge Liu             if (sparePartNumber != nullptr && !sparePartNumber->empty())
3262b45fb3bSGeorge Liu             {
3272b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
3282b45fb3bSGeorge Liu             }
329b5190062SHieu Huynh 
330b5190062SHieu Huynh             if (buildDate != nullptr)
331b5190062SHieu Huynh             {
332b5190062SHieu Huynh                 time_utils::productionDateReport(asyncResp->res, *buildDate);
333b5190062SHieu Huynh             }
3342b45fb3bSGeorge Liu         });
3352b45fb3bSGeorge Liu }
3362b45fb3bSGeorge Liu 
337a0dba87bSGeorge Liu inline void getPowerSupplyFirmwareVersion(
338a0dba87bSGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
339a0dba87bSGeorge Liu     const std::string& service, const std::string& path)
340a0dba87bSGeorge Liu {
341deae6a78SEd Tanous     dbus::utility::getProperty<std::string>(
342deae6a78SEd Tanous         service, path, "xyz.openbmc_project.Software.Version", "Version",
343a0dba87bSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
344a0dba87bSGeorge Liu                     const std::string& value) {
345a0dba87bSGeorge Liu             if (ec)
346a0dba87bSGeorge Liu             {
347a0dba87bSGeorge Liu                 if (ec.value() != EBADR)
348a0dba87bSGeorge Liu                 {
349bd79bce8SPatrick Williams                     BMCWEB_LOG_ERROR(
350bd79bce8SPatrick Williams                         "DBUS response error for FirmwareVersion {}",
35162598e31SEd Tanous                         ec.value());
352a0dba87bSGeorge Liu                     messages::internalError(asyncResp->res);
353a0dba87bSGeorge Liu                 }
354a0dba87bSGeorge Liu                 return;
355a0dba87bSGeorge Liu             }
356a0dba87bSGeorge Liu             asyncResp->res.jsonValue["FirmwareVersion"] = value;
357a0dba87bSGeorge Liu         });
358a0dba87bSGeorge Liu }
359a0dba87bSGeorge Liu 
3602b45fb3bSGeorge Liu inline void
36144845e5fSGeorge Liu     getPowerSupplyLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
36244845e5fSGeorge Liu                            const std::string& service, const std::string& path)
36344845e5fSGeorge Liu {
364deae6a78SEd Tanous     dbus::utility::getProperty<std::string>(
365deae6a78SEd Tanous         service, path, "xyz.openbmc_project.Inventory.Decorator.LocationCode",
366deae6a78SEd Tanous         "LocationCode",
36744845e5fSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
36844845e5fSGeorge Liu                     const std::string& value) {
36944845e5fSGeorge Liu             if (ec)
37044845e5fSGeorge Liu             {
37144845e5fSGeorge Liu                 if (ec.value() != EBADR)
37244845e5fSGeorge Liu                 {
37362598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Location {}",
37462598e31SEd Tanous                                      ec.value());
37544845e5fSGeorge Liu                     messages::internalError(asyncResp->res);
37644845e5fSGeorge Liu                 }
37744845e5fSGeorge Liu                 return;
37844845e5fSGeorge Liu             }
379bd79bce8SPatrick Williams             asyncResp->res
380bd79bce8SPatrick Williams                 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = value;
38144845e5fSGeorge Liu         });
38244845e5fSGeorge Liu }
38344845e5fSGeorge Liu 
384ddceee07SGeorge Liu inline void handleGetEfficiencyResponse(
385ddceee07SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
386ddceee07SGeorge Liu     const boost::system::error_code& ec, uint32_t value)
387ddceee07SGeorge Liu {
388ddceee07SGeorge Liu     if (ec)
389ddceee07SGeorge Liu     {
390ddceee07SGeorge Liu         if (ec.value() != EBADR)
391ddceee07SGeorge Liu         {
39262598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for DeratingFactor {}",
39362598e31SEd Tanous                              ec.value());
394ddceee07SGeorge Liu             messages::internalError(asyncResp->res);
395ddceee07SGeorge Liu         }
396ddceee07SGeorge Liu         return;
397ddceee07SGeorge Liu     }
398ddceee07SGeorge Liu     // The PDI default value is 0, if it hasn't been set leave off
399ddceee07SGeorge Liu     if (value == 0)
400ddceee07SGeorge Liu     {
401ddceee07SGeorge Liu         return;
402ddceee07SGeorge Liu     }
403ddceee07SGeorge Liu 
404ddceee07SGeorge Liu     nlohmann::json::array_t efficiencyRatings;
405ddceee07SGeorge Liu     nlohmann::json::object_t efficiencyPercent;
406ddceee07SGeorge Liu     efficiencyPercent["EfficiencyPercent"] = value;
407ddceee07SGeorge Liu     efficiencyRatings.emplace_back(std::move(efficiencyPercent));
408ddceee07SGeorge Liu     asyncResp->res.jsonValue["EfficiencyRatings"] =
409ddceee07SGeorge Liu         std::move(efficiencyRatings);
410ddceee07SGeorge Liu }
411ddceee07SGeorge Liu 
412ddceee07SGeorge Liu inline void handlePowerSupplyAttributesSubTreeResponse(
413ddceee07SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
414ddceee07SGeorge Liu     const boost::system::error_code& ec,
415ddceee07SGeorge Liu     const dbus::utility::MapperGetSubTreeResponse& subtree)
416ddceee07SGeorge Liu {
417ddceee07SGeorge Liu     if (ec)
418ddceee07SGeorge Liu     {
419ddceee07SGeorge Liu         if (ec.value() != EBADR)
420ddceee07SGeorge Liu         {
42162598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for EfficiencyPercent {}",
42262598e31SEd Tanous                              ec.value());
423ddceee07SGeorge Liu             messages::internalError(asyncResp->res);
424ddceee07SGeorge Liu         }
425ddceee07SGeorge Liu         return;
426ddceee07SGeorge Liu     }
427ddceee07SGeorge Liu 
428ddceee07SGeorge Liu     if (subtree.empty())
429ddceee07SGeorge Liu     {
43062598e31SEd Tanous         BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
431ddceee07SGeorge Liu         return;
432ddceee07SGeorge Liu     }
433ddceee07SGeorge Liu 
434ddceee07SGeorge Liu     if (subtree.size() != 1)
435ddceee07SGeorge Liu     {
43662598e31SEd Tanous         BMCWEB_LOG_ERROR(
43762598e31SEd Tanous             "Unexpected number of paths returned by getSubTree: {}",
43862598e31SEd Tanous             subtree.size());
439ddceee07SGeorge Liu         messages::internalError(asyncResp->res);
440ddceee07SGeorge Liu         return;
441ddceee07SGeorge Liu     }
442ddceee07SGeorge Liu 
443ddceee07SGeorge Liu     const auto& [path, serviceMap] = *subtree.begin();
444ddceee07SGeorge Liu     const auto& [service, interfaces] = *serviceMap.begin();
445deae6a78SEd Tanous     dbus::utility::getProperty<uint32_t>(
446deae6a78SEd Tanous         service, path, "xyz.openbmc_project.Control.PowerSupplyAttributes",
447deae6a78SEd Tanous         "DeratingFactor",
448ddceee07SGeorge Liu         [asyncResp](const boost::system::error_code& ec1, uint32_t value) {
449ddceee07SGeorge Liu             handleGetEfficiencyResponse(asyncResp, ec1, value);
450ddceee07SGeorge Liu         });
451ddceee07SGeorge Liu }
452ddceee07SGeorge Liu 
453ddceee07SGeorge Liu inline void
454ddceee07SGeorge Liu     getEfficiencyPercent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
455ddceee07SGeorge Liu {
456ddceee07SGeorge Liu     constexpr std::array<std::string_view, 1> efficiencyIntf = {
457ddceee07SGeorge Liu         "xyz.openbmc_project.Control.PowerSupplyAttributes"};
458ddceee07SGeorge Liu 
459ddceee07SGeorge Liu     dbus::utility::getSubTree(
460ddceee07SGeorge Liu         "/xyz/openbmc_project", 0, efficiencyIntf,
461ddceee07SGeorge Liu         [asyncResp](const boost::system::error_code& ec,
462ddceee07SGeorge Liu                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
463ddceee07SGeorge Liu             handlePowerSupplyAttributesSubTreeResponse(asyncResp, ec, subtree);
464ddceee07SGeorge Liu         });
465ddceee07SGeorge Liu }
466ddceee07SGeorge Liu 
467bd79bce8SPatrick Williams inline void doPowerSupplyGet(
468bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
469bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& powerSupplyId,
4703e42a329SLakshmi Yadlapati     const std::string& powerSupplyPath, const std::string& service)
47100ef5dc6SGeorge Liu {
47200ef5dc6SGeorge Liu     asyncResp->res.addHeader(
47300ef5dc6SGeorge Liu         boost::beast::http::field::link,
47400ef5dc6SGeorge Liu         "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
4753e42a329SLakshmi Yadlapati     asyncResp->res.jsonValue["@odata.type"] = "#PowerSupply.v1_5_0.PowerSupply";
47600ef5dc6SGeorge Liu     asyncResp->res.jsonValue["Name"] = "Power Supply";
47700ef5dc6SGeorge Liu     asyncResp->res.jsonValue["Id"] = powerSupplyId;
47800ef5dc6SGeorge Liu     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
4793e42a329SLakshmi Yadlapati         "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
4803e42a329SLakshmi Yadlapati         powerSupplyId);
48134dfcb94SGeorge Liu 
4823e42a329SLakshmi Yadlapati     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
483539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
48434dfcb94SGeorge Liu 
4853e42a329SLakshmi Yadlapati     getPowerSupplyState(asyncResp, service, powerSupplyPath);
4863e42a329SLakshmi Yadlapati     getPowerSupplyHealth(asyncResp, service, powerSupplyPath);
4873e42a329SLakshmi Yadlapati     getPowerSupplyAsset(asyncResp, service, powerSupplyPath);
4883e42a329SLakshmi Yadlapati     getPowerSupplyFirmwareVersion(asyncResp, service, powerSupplyPath);
4893e42a329SLakshmi Yadlapati     getPowerSupplyLocation(asyncResp, service, powerSupplyPath);
490ddceee07SGeorge Liu     getEfficiencyPercent(asyncResp);
49100ef5dc6SGeorge Liu }
49200ef5dc6SGeorge Liu 
493bd79bce8SPatrick Williams inline void handlePowerSupplyHead(
494bd79bce8SPatrick Williams     App& app, const crow::Request& req,
49500ef5dc6SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
496bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& powerSupplyId)
49700ef5dc6SGeorge Liu {
49800ef5dc6SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
49900ef5dc6SGeorge Liu     {
50000ef5dc6SGeorge Liu         return;
50100ef5dc6SGeorge Liu     }
50200ef5dc6SGeorge Liu 
50300ef5dc6SGeorge Liu     // Get the correct Path and Service that match the input parameters
504bd79bce8SPatrick Williams     getValidPowerSupplyPath(
5053e42a329SLakshmi Yadlapati         asyncResp, chassisId, powerSupplyId,
5063e42a329SLakshmi Yadlapati         [asyncResp](const std::string&, const std::string&) {
50700ef5dc6SGeorge Liu             asyncResp->res.addHeader(
50800ef5dc6SGeorge Liu                 boost::beast::http::field::link,
50900ef5dc6SGeorge Liu                 "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
51000ef5dc6SGeorge Liu         });
51100ef5dc6SGeorge Liu }
51200ef5dc6SGeorge Liu 
513bd79bce8SPatrick Williams inline void handlePowerSupplyGet(
514bd79bce8SPatrick Williams     App& app, const crow::Request& req,
51500ef5dc6SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
516bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& powerSupplyId)
51700ef5dc6SGeorge Liu {
51800ef5dc6SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
51900ef5dc6SGeorge Liu     {
52000ef5dc6SGeorge Liu         return;
52100ef5dc6SGeorge Liu     }
5223e42a329SLakshmi Yadlapati     getValidPowerSupplyPath(
5233e42a329SLakshmi Yadlapati         asyncResp, chassisId, powerSupplyId,
52400ef5dc6SGeorge Liu         std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId));
52500ef5dc6SGeorge Liu }
52600ef5dc6SGeorge Liu 
52700ef5dc6SGeorge Liu inline void requestRoutesPowerSupply(App& app)
52800ef5dc6SGeorge Liu {
52900ef5dc6SGeorge Liu     BMCWEB_ROUTE(
53000ef5dc6SGeorge Liu         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
53100ef5dc6SGeorge Liu         .privileges(redfish::privileges::headPowerSupply)
53200ef5dc6SGeorge Liu         .methods(boost::beast::http::verb::head)(
53300ef5dc6SGeorge Liu             std::bind_front(handlePowerSupplyHead, std::ref(app)));
53400ef5dc6SGeorge Liu 
53500ef5dc6SGeorge Liu     BMCWEB_ROUTE(
53600ef5dc6SGeorge Liu         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
53700ef5dc6SGeorge Liu         .privileges(redfish::privileges::getPowerSupply)
53800ef5dc6SGeorge Liu         .methods(boost::beast::http::verb::get)(
53900ef5dc6SGeorge Liu             std::bind_front(handlePowerSupplyGet, std::ref(app)));
54000ef5dc6SGeorge Liu }
54100ef5dc6SGeorge Liu 
542a7210020SGeorge Liu } // namespace redfish
543