xref: /openbmc/bmcweb/features/redfish/lib/power_supply.hpp (revision ddceee0705182270d0643774d494df4a7f1d028f)
1a7210020SGeorge Liu #pragma once
2a7210020SGeorge Liu 
3a7210020SGeorge Liu #include "app.hpp"
4a7210020SGeorge Liu #include "dbus_utility.hpp"
5a7210020SGeorge Liu #include "query.hpp"
6a7210020SGeorge Liu #include "registries/privilege_registry.hpp"
7a7210020SGeorge Liu #include "utils/chassis_utils.hpp"
82b45fb3bSGeorge Liu #include "utils/dbus_utils.hpp"
92b45fb3bSGeorge Liu #include "utils/json_utils.hpp"
10a7210020SGeorge Liu 
1134dfcb94SGeorge Liu #include <boost/system/error_code.hpp>
12ef4c65b7SEd Tanous #include <boost/url/format.hpp>
13ef4c65b7SEd Tanous 
14a7210020SGeorge Liu #include <memory>
15a7210020SGeorge Liu #include <optional>
16a7210020SGeorge Liu #include <string>
17a7210020SGeorge Liu 
18a7210020SGeorge Liu namespace redfish
19a7210020SGeorge Liu {
20a7210020SGeorge Liu 
21788fe6cfSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> powerSupplyInterface = {
22788fe6cfSLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PowerSupply"};
23788fe6cfSLakshmi Yadlapati 
24788fe6cfSLakshmi Yadlapati inline void updatePowerSupplyList(
25788fe6cfSLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2600ef5dc6SGeorge Liu     const std::string& chassisId,
27788fe6cfSLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& powerSupplyPaths)
28788fe6cfSLakshmi Yadlapati {
29788fe6cfSLakshmi Yadlapati     nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"];
30788fe6cfSLakshmi Yadlapati     for (const std::string& powerSupplyPath : powerSupplyPaths)
31a7210020SGeorge Liu     {
3200ef5dc6SGeorge Liu         std::string powerSupplyName =
3300ef5dc6SGeorge Liu             sdbusplus::message::object_path(powerSupplyPath).filename();
3400ef5dc6SGeorge Liu         if (powerSupplyName.empty())
3500ef5dc6SGeorge Liu         {
36788fe6cfSLakshmi Yadlapati             continue;
3700ef5dc6SGeorge Liu         }
3800ef5dc6SGeorge Liu 
3900ef5dc6SGeorge Liu         nlohmann::json item = nlohmann::json::object();
4000ef5dc6SGeorge Liu         item["@odata.id"] = boost::urls::format(
4100ef5dc6SGeorge Liu             "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
4200ef5dc6SGeorge Liu             powerSupplyName);
4300ef5dc6SGeorge Liu 
4400ef5dc6SGeorge Liu         powerSupplyList.emplace_back(std::move(item));
45788fe6cfSLakshmi Yadlapati     }
4600ef5dc6SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size();
47a7210020SGeorge Liu }
48a7210020SGeorge Liu 
49a7210020SGeorge Liu inline void
50a7210020SGeorge Liu     doPowerSupplyCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
51a7210020SGeorge Liu                             const std::string& chassisId,
52a7210020SGeorge Liu                             const std::optional<std::string>& validChassisPath)
53a7210020SGeorge Liu {
54a7210020SGeorge Liu     if (!validChassisPath)
55a7210020SGeorge Liu     {
56a7210020SGeorge Liu         messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
57a7210020SGeorge Liu         return;
58a7210020SGeorge Liu     }
59a7210020SGeorge Liu 
60a7210020SGeorge Liu     asyncResp->res.addHeader(
61a7210020SGeorge Liu         boost::beast::http::field::link,
62a7210020SGeorge Liu         "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
63a7210020SGeorge Liu     asyncResp->res.jsonValue["@odata.type"] =
64a7210020SGeorge Liu         "#PowerSupplyCollection.PowerSupplyCollection";
65a7210020SGeorge Liu     asyncResp->res.jsonValue["Name"] = "Power Supply Collection";
66ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
67ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId);
68a7210020SGeorge Liu     asyncResp->res.jsonValue["Description"] =
69a7210020SGeorge Liu         "The collection of PowerSupply resource instances.";
707a2bb2c9SGeorge Liu     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
717a2bb2c9SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = 0;
72a7210020SGeorge Liu 
73a7210020SGeorge Liu     std::string powerPath = *validChassisPath + "/powered_by";
74788fe6cfSLakshmi Yadlapati     dbus::utility::getAssociatedSubTreePaths(
75788fe6cfSLakshmi Yadlapati         powerPath,
76788fe6cfSLakshmi Yadlapati         sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
77788fe6cfSLakshmi Yadlapati         powerSupplyInterface,
78788fe6cfSLakshmi Yadlapati         [asyncResp, chassisId](
79a7210020SGeorge Liu             const boost::system::error_code& ec,
80788fe6cfSLakshmi Yadlapati             const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
81a7210020SGeorge Liu         if (ec)
82a7210020SGeorge Liu         {
83a7210020SGeorge Liu             if (ec.value() != EBADR)
84a7210020SGeorge Liu             {
85a7210020SGeorge Liu                 BMCWEB_LOG_ERROR << "DBUS response error" << ec.value();
86a7210020SGeorge Liu                 messages::internalError(asyncResp->res);
87a7210020SGeorge Liu             }
88a7210020SGeorge Liu             return;
89a7210020SGeorge Liu         }
90a7210020SGeorge Liu 
91788fe6cfSLakshmi Yadlapati         updatePowerSupplyList(asyncResp, chassisId, subtreePaths);
92a7210020SGeorge Liu         });
93a7210020SGeorge Liu }
94a7210020SGeorge Liu 
95a7210020SGeorge Liu inline void handlePowerSupplyCollectionHead(
96a7210020SGeorge Liu     App& app, const crow::Request& req,
97a7210020SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
98a7210020SGeorge Liu     const std::string& chassisId)
99a7210020SGeorge Liu {
100a7210020SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
101a7210020SGeorge Liu     {
102a7210020SGeorge Liu         return;
103a7210020SGeorge Liu     }
104a7210020SGeorge Liu 
105a7210020SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
106a7210020SGeorge Liu         asyncResp, chassisId,
107a7210020SGeorge Liu         [asyncResp,
108a7210020SGeorge Liu          chassisId](const std::optional<std::string>& validChassisPath) {
109a7210020SGeorge Liu         if (!validChassisPath)
110a7210020SGeorge Liu         {
111a7210020SGeorge Liu             messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
112a7210020SGeorge Liu             return;
113a7210020SGeorge Liu         }
114a7210020SGeorge Liu         asyncResp->res.addHeader(
115a7210020SGeorge Liu             boost::beast::http::field::link,
116a7210020SGeorge Liu             "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
117a7210020SGeorge Liu         });
118a7210020SGeorge Liu }
119a7210020SGeorge Liu 
120a7210020SGeorge Liu inline void handlePowerSupplyCollectionGet(
121a7210020SGeorge Liu     App& app, const crow::Request& req,
122a7210020SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
123a7210020SGeorge Liu     const std::string& chassisId)
124a7210020SGeorge Liu {
125a7210020SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
126a7210020SGeorge Liu     {
127a7210020SGeorge Liu         return;
128a7210020SGeorge Liu     }
129a7210020SGeorge Liu 
130a7210020SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
131a7210020SGeorge Liu         asyncResp, chassisId,
132a7210020SGeorge Liu         std::bind_front(doPowerSupplyCollection, asyncResp, chassisId));
133a7210020SGeorge Liu }
134a7210020SGeorge Liu 
135a7210020SGeorge Liu inline void requestRoutesPowerSupplyCollection(App& app)
136a7210020SGeorge Liu {
137a7210020SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
138a7210020SGeorge Liu         .privileges(redfish::privileges::headPowerSupplyCollection)
139a7210020SGeorge Liu         .methods(boost::beast::http::verb::head)(
140a7210020SGeorge Liu             std::bind_front(handlePowerSupplyCollectionHead, std::ref(app)));
141a7210020SGeorge Liu 
142a7210020SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
143a7210020SGeorge Liu         .privileges(redfish::privileges::getPowerSupplyCollection)
144a7210020SGeorge Liu         .methods(boost::beast::http::verb::get)(
145a7210020SGeorge Liu             std::bind_front(handlePowerSupplyCollectionGet, std::ref(app)));
146a7210020SGeorge Liu }
147a7210020SGeorge Liu 
14800ef5dc6SGeorge Liu inline bool checkPowerSupplyId(const std::string& powerSupplyPath,
14900ef5dc6SGeorge Liu                                const std::string& powerSupplyId)
15000ef5dc6SGeorge Liu {
15100ef5dc6SGeorge Liu     std::string powerSupplyName =
15200ef5dc6SGeorge Liu         sdbusplus::message::object_path(powerSupplyPath).filename();
15300ef5dc6SGeorge Liu 
15400ef5dc6SGeorge Liu     return !(powerSupplyName.empty() || powerSupplyName != powerSupplyId);
15500ef5dc6SGeorge Liu }
15600ef5dc6SGeorge Liu 
15734dfcb94SGeorge Liu inline void getValidPowerSupplyPath(
15834dfcb94SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
15934dfcb94SGeorge Liu     const std::string& validChassisPath, const std::string& powerSupplyId,
16034dfcb94SGeorge Liu     std::function<void(const std::string& powerSupplyPath)>&& callback)
16100ef5dc6SGeorge Liu {
16200ef5dc6SGeorge Liu     std::string powerPath = validChassisPath + "/powered_by";
163788fe6cfSLakshmi Yadlapati     dbus::utility::getAssociatedSubTreePaths(
164788fe6cfSLakshmi Yadlapati         powerPath,
165788fe6cfSLakshmi Yadlapati         sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
166788fe6cfSLakshmi Yadlapati         powerSupplyInterface,
167788fe6cfSLakshmi Yadlapati         [asyncResp, powerSupplyId, callback{std::move(callback)}](
16800ef5dc6SGeorge Liu             const boost::system::error_code& ec,
169788fe6cfSLakshmi Yadlapati             const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
17000ef5dc6SGeorge Liu         if (ec)
17100ef5dc6SGeorge Liu         {
17200ef5dc6SGeorge Liu             if (ec.value() != EBADR)
17300ef5dc6SGeorge Liu             {
17400ef5dc6SGeorge Liu                 BMCWEB_LOG_ERROR
175788fe6cfSLakshmi Yadlapati                     << "DBUS response error for getAssociatedSubTreePaths"
17600ef5dc6SGeorge Liu                     << ec.value();
17700ef5dc6SGeorge Liu                 messages::internalError(asyncResp->res);
17800ef5dc6SGeorge Liu                 return;
17900ef5dc6SGeorge Liu             }
18000ef5dc6SGeorge Liu             messages::resourceNotFound(asyncResp->res, "PowerSupplies",
18100ef5dc6SGeorge Liu                                        powerSupplyId);
18200ef5dc6SGeorge Liu             return;
18300ef5dc6SGeorge Liu         }
18400ef5dc6SGeorge Liu 
185788fe6cfSLakshmi Yadlapati         for (const std::string& path : subtreePaths)
18600ef5dc6SGeorge Liu         {
187788fe6cfSLakshmi Yadlapati             if (checkPowerSupplyId(path, powerSupplyId))
18800ef5dc6SGeorge Liu             {
189788fe6cfSLakshmi Yadlapati                 callback(path);
19000ef5dc6SGeorge Liu                 return;
19100ef5dc6SGeorge Liu             }
19200ef5dc6SGeorge Liu         }
19300ef5dc6SGeorge Liu 
194788fe6cfSLakshmi Yadlapati         if (!subtreePaths.empty())
19500ef5dc6SGeorge Liu         {
196788fe6cfSLakshmi Yadlapati             BMCWEB_LOG_WARNING << "Power supply not found: " << powerSupplyId;
19700ef5dc6SGeorge Liu             messages::resourceNotFound(asyncResp->res, "PowerSupplies",
19800ef5dc6SGeorge Liu                                        powerSupplyId);
19900ef5dc6SGeorge Liu             return;
20000ef5dc6SGeorge Liu         }
20100ef5dc6SGeorge Liu         });
20200ef5dc6SGeorge Liu }
20300ef5dc6SGeorge Liu 
20400ef5dc6SGeorge Liu inline void
20534dfcb94SGeorge Liu     getPowerSupplyState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
20634dfcb94SGeorge Liu                         const std::string& service, const std::string& path)
20734dfcb94SGeorge Liu {
20834dfcb94SGeorge Liu     sdbusplus::asio::getProperty<bool>(
20934dfcb94SGeorge Liu         *crow::connections::systemBus, service, path,
21034dfcb94SGeorge Liu         "xyz.openbmc_project.Inventory.Item", "Present",
21134dfcb94SGeorge Liu         [asyncResp](const boost::system::error_code& ec, const bool value) {
21234dfcb94SGeorge Liu         if (ec)
21334dfcb94SGeorge Liu         {
21434dfcb94SGeorge Liu             if (ec.value() != EBADR)
21534dfcb94SGeorge Liu             {
21634dfcb94SGeorge Liu                 BMCWEB_LOG_ERROR << "DBUS response error for State "
21734dfcb94SGeorge Liu                                  << ec.value();
21834dfcb94SGeorge Liu                 messages::internalError(asyncResp->res);
21934dfcb94SGeorge Liu             }
22034dfcb94SGeorge Liu             return;
22134dfcb94SGeorge Liu         }
22234dfcb94SGeorge Liu 
22334dfcb94SGeorge Liu         if (!value)
22434dfcb94SGeorge Liu         {
22534dfcb94SGeorge Liu             asyncResp->res.jsonValue["Status"]["State"] = "Absent";
22634dfcb94SGeorge Liu         }
22734dfcb94SGeorge Liu         });
22834dfcb94SGeorge Liu }
22934dfcb94SGeorge Liu 
23034dfcb94SGeorge Liu inline void
23134dfcb94SGeorge Liu     getPowerSupplyHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
23234dfcb94SGeorge Liu                          const std::string& service, const std::string& path)
23334dfcb94SGeorge Liu {
23434dfcb94SGeorge Liu     sdbusplus::asio::getProperty<bool>(
23534dfcb94SGeorge Liu         *crow::connections::systemBus, service, path,
23634dfcb94SGeorge Liu         "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
23734dfcb94SGeorge Liu         [asyncResp](const boost::system::error_code& ec, const bool value) {
23834dfcb94SGeorge Liu         if (ec)
23934dfcb94SGeorge Liu         {
24034dfcb94SGeorge Liu             if (ec.value() != EBADR)
24134dfcb94SGeorge Liu             {
24234dfcb94SGeorge Liu                 BMCWEB_LOG_ERROR << "DBUS response error for Health "
24334dfcb94SGeorge Liu                                  << ec.value();
24434dfcb94SGeorge Liu                 messages::internalError(asyncResp->res);
24534dfcb94SGeorge Liu             }
24634dfcb94SGeorge Liu             return;
24734dfcb94SGeorge Liu         }
24834dfcb94SGeorge Liu 
24934dfcb94SGeorge Liu         if (!value)
25034dfcb94SGeorge Liu         {
25134dfcb94SGeorge Liu             asyncResp->res.jsonValue["Status"]["Health"] = "Critical";
25234dfcb94SGeorge Liu         }
25334dfcb94SGeorge Liu         });
25434dfcb94SGeorge Liu }
25534dfcb94SGeorge Liu 
25634dfcb94SGeorge Liu inline void
2572b45fb3bSGeorge Liu     getPowerSupplyAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2582b45fb3bSGeorge Liu                         const std::string& service, const std::string& path)
2592b45fb3bSGeorge Liu {
2602b45fb3bSGeorge Liu     sdbusplus::asio::getAllProperties(
2612b45fb3bSGeorge Liu         *crow::connections::systemBus, service, path,
2622b45fb3bSGeorge Liu         "xyz.openbmc_project.Inventory.Decorator.Asset",
2632b45fb3bSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
2642b45fb3bSGeorge Liu                     const dbus::utility::DBusPropertiesMap& propertiesList) {
2652b45fb3bSGeorge Liu         if (ec)
2662b45fb3bSGeorge Liu         {
2672b45fb3bSGeorge Liu             if (ec.value() != EBADR)
2682b45fb3bSGeorge Liu             {
2692b45fb3bSGeorge Liu                 BMCWEB_LOG_ERROR << "DBUS response error for Asset "
2702b45fb3bSGeorge Liu                                  << ec.value();
2712b45fb3bSGeorge Liu                 messages::internalError(asyncResp->res);
2722b45fb3bSGeorge Liu             }
2732b45fb3bSGeorge Liu             return;
2742b45fb3bSGeorge Liu         }
2752b45fb3bSGeorge Liu 
2762b45fb3bSGeorge Liu         const std::string* partNumber = nullptr;
2772b45fb3bSGeorge Liu         const std::string* serialNumber = nullptr;
2782b45fb3bSGeorge Liu         const std::string* manufacturer = nullptr;
2792b45fb3bSGeorge Liu         const std::string* model = nullptr;
2802b45fb3bSGeorge Liu         const std::string* sparePartNumber = nullptr;
2812b45fb3bSGeorge Liu 
2822b45fb3bSGeorge Liu         const bool success = sdbusplus::unpackPropertiesNoThrow(
2832b45fb3bSGeorge Liu             dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
2842b45fb3bSGeorge Liu             partNumber, "SerialNumber", serialNumber, "Manufacturer",
2852b45fb3bSGeorge Liu             manufacturer, "Model", model, "SparePartNumber", sparePartNumber);
2862b45fb3bSGeorge Liu 
2872b45fb3bSGeorge Liu         if (!success)
2882b45fb3bSGeorge Liu         {
2892b45fb3bSGeorge Liu             messages::internalError(asyncResp->res);
2902b45fb3bSGeorge Liu             return;
2912b45fb3bSGeorge Liu         }
2922b45fb3bSGeorge Liu 
2932b45fb3bSGeorge Liu         if (partNumber != nullptr)
2942b45fb3bSGeorge Liu         {
2952b45fb3bSGeorge Liu             asyncResp->res.jsonValue["PartNumber"] = *partNumber;
2962b45fb3bSGeorge Liu         }
2972b45fb3bSGeorge Liu 
2982b45fb3bSGeorge Liu         if (serialNumber != nullptr)
2992b45fb3bSGeorge Liu         {
3002b45fb3bSGeorge Liu             asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
3012b45fb3bSGeorge Liu         }
3022b45fb3bSGeorge Liu 
3032b45fb3bSGeorge Liu         if (manufacturer != nullptr)
3042b45fb3bSGeorge Liu         {
3052b45fb3bSGeorge Liu             asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
3062b45fb3bSGeorge Liu         }
3072b45fb3bSGeorge Liu 
3082b45fb3bSGeorge Liu         if (model != nullptr)
3092b45fb3bSGeorge Liu         {
3102b45fb3bSGeorge Liu             asyncResp->res.jsonValue["Model"] = *model;
3112b45fb3bSGeorge Liu         }
3122b45fb3bSGeorge Liu 
3132b45fb3bSGeorge Liu         // SparePartNumber is optional on D-Bus so skip if it is empty
3142b45fb3bSGeorge Liu         if (sparePartNumber != nullptr && !sparePartNumber->empty())
3152b45fb3bSGeorge Liu         {
3162b45fb3bSGeorge Liu             asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
3172b45fb3bSGeorge Liu         }
3182b45fb3bSGeorge Liu         });
3192b45fb3bSGeorge Liu }
3202b45fb3bSGeorge Liu 
321a0dba87bSGeorge Liu inline void getPowerSupplyFirmwareVersion(
322a0dba87bSGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
323a0dba87bSGeorge Liu     const std::string& service, const std::string& path)
324a0dba87bSGeorge Liu {
325a0dba87bSGeorge Liu     sdbusplus::asio::getProperty<std::string>(
326a0dba87bSGeorge Liu         *crow::connections::systemBus, service, path,
327a0dba87bSGeorge Liu         "xyz.openbmc_project.Software.Version", "Version",
328a0dba87bSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
329a0dba87bSGeorge Liu                     const std::string& value) {
330a0dba87bSGeorge Liu         if (ec)
331a0dba87bSGeorge Liu         {
332a0dba87bSGeorge Liu             if (ec.value() != EBADR)
333a0dba87bSGeorge Liu             {
334a0dba87bSGeorge Liu                 BMCWEB_LOG_ERROR << "DBUS response error for FirmwareVersion "
335a0dba87bSGeorge Liu                                  << ec.value();
336a0dba87bSGeorge Liu                 messages::internalError(asyncResp->res);
337a0dba87bSGeorge Liu             }
338a0dba87bSGeorge Liu             return;
339a0dba87bSGeorge Liu         }
340a0dba87bSGeorge Liu         asyncResp->res.jsonValue["FirmwareVersion"] = value;
341a0dba87bSGeorge Liu         });
342a0dba87bSGeorge Liu }
343a0dba87bSGeorge Liu 
3442b45fb3bSGeorge Liu inline void
34544845e5fSGeorge Liu     getPowerSupplyLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
34644845e5fSGeorge Liu                            const std::string& service, const std::string& path)
34744845e5fSGeorge Liu {
34844845e5fSGeorge Liu     sdbusplus::asio::getProperty<std::string>(
34944845e5fSGeorge Liu         *crow::connections::systemBus, service, path,
35044845e5fSGeorge Liu         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
35144845e5fSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
35244845e5fSGeorge Liu                     const std::string& value) {
35344845e5fSGeorge Liu         if (ec)
35444845e5fSGeorge Liu         {
35544845e5fSGeorge Liu             if (ec.value() != EBADR)
35644845e5fSGeorge Liu             {
35744845e5fSGeorge Liu                 BMCWEB_LOG_ERROR << "DBUS response error for Location "
35844845e5fSGeorge Liu                                  << ec.value();
35944845e5fSGeorge Liu                 messages::internalError(asyncResp->res);
36044845e5fSGeorge Liu             }
36144845e5fSGeorge Liu             return;
36244845e5fSGeorge Liu         }
36344845e5fSGeorge Liu         asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
36444845e5fSGeorge Liu             value;
36544845e5fSGeorge Liu         });
36644845e5fSGeorge Liu }
36744845e5fSGeorge Liu 
368*ddceee07SGeorge Liu inline void handleGetEfficiencyResponse(
369*ddceee07SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
370*ddceee07SGeorge Liu     const boost::system::error_code& ec, uint32_t value)
371*ddceee07SGeorge Liu {
372*ddceee07SGeorge Liu     if (ec)
373*ddceee07SGeorge Liu     {
374*ddceee07SGeorge Liu         if (ec.value() != EBADR)
375*ddceee07SGeorge Liu         {
376*ddceee07SGeorge Liu             BMCWEB_LOG_ERROR << "DBUS response error for DeratingFactor "
377*ddceee07SGeorge Liu                              << ec.value();
378*ddceee07SGeorge Liu             messages::internalError(asyncResp->res);
379*ddceee07SGeorge Liu         }
380*ddceee07SGeorge Liu         return;
381*ddceee07SGeorge Liu     }
382*ddceee07SGeorge Liu     // The PDI default value is 0, if it hasn't been set leave off
383*ddceee07SGeorge Liu     if (value == 0)
384*ddceee07SGeorge Liu     {
385*ddceee07SGeorge Liu         return;
386*ddceee07SGeorge Liu     }
387*ddceee07SGeorge Liu 
388*ddceee07SGeorge Liu     nlohmann::json::array_t efficiencyRatings;
389*ddceee07SGeorge Liu     nlohmann::json::object_t efficiencyPercent;
390*ddceee07SGeorge Liu     efficiencyPercent["EfficiencyPercent"] = value;
391*ddceee07SGeorge Liu     efficiencyRatings.emplace_back(std::move(efficiencyPercent));
392*ddceee07SGeorge Liu     asyncResp->res.jsonValue["EfficiencyRatings"] =
393*ddceee07SGeorge Liu         std::move(efficiencyRatings);
394*ddceee07SGeorge Liu }
395*ddceee07SGeorge Liu 
396*ddceee07SGeorge Liu inline void handlePowerSupplyAttributesSubTreeResponse(
397*ddceee07SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
398*ddceee07SGeorge Liu     const boost::system::error_code& ec,
399*ddceee07SGeorge Liu     const dbus::utility::MapperGetSubTreeResponse& subtree)
400*ddceee07SGeorge Liu {
401*ddceee07SGeorge Liu     if (ec)
402*ddceee07SGeorge Liu     {
403*ddceee07SGeorge Liu         if (ec.value() != EBADR)
404*ddceee07SGeorge Liu         {
405*ddceee07SGeorge Liu             BMCWEB_LOG_ERROR << "DBUS response error for EfficiencyPercent "
406*ddceee07SGeorge Liu                              << ec.value();
407*ddceee07SGeorge Liu             messages::internalError(asyncResp->res);
408*ddceee07SGeorge Liu         }
409*ddceee07SGeorge Liu         return;
410*ddceee07SGeorge Liu     }
411*ddceee07SGeorge Liu 
412*ddceee07SGeorge Liu     if (subtree.empty())
413*ddceee07SGeorge Liu     {
414*ddceee07SGeorge Liu         BMCWEB_LOG_DEBUG << "Can't find Power Supply Attributes!";
415*ddceee07SGeorge Liu         return;
416*ddceee07SGeorge Liu     }
417*ddceee07SGeorge Liu 
418*ddceee07SGeorge Liu     if (subtree.size() != 1)
419*ddceee07SGeorge Liu     {
420*ddceee07SGeorge Liu         BMCWEB_LOG_ERROR
421*ddceee07SGeorge Liu             << "Unexpected number of paths returned by getSubTree: "
422*ddceee07SGeorge Liu             << subtree.size();
423*ddceee07SGeorge Liu         messages::internalError(asyncResp->res);
424*ddceee07SGeorge Liu         return;
425*ddceee07SGeorge Liu     }
426*ddceee07SGeorge Liu 
427*ddceee07SGeorge Liu     const auto& [path, serviceMap] = *subtree.begin();
428*ddceee07SGeorge Liu     const auto& [service, interfaces] = *serviceMap.begin();
429*ddceee07SGeorge Liu     sdbusplus::asio::getProperty<uint32_t>(
430*ddceee07SGeorge Liu         *crow::connections::systemBus, service, path,
431*ddceee07SGeorge Liu         "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
432*ddceee07SGeorge Liu         [asyncResp](const boost::system::error_code& ec1, uint32_t value) {
433*ddceee07SGeorge Liu         handleGetEfficiencyResponse(asyncResp, ec1, value);
434*ddceee07SGeorge Liu         });
435*ddceee07SGeorge Liu }
436*ddceee07SGeorge Liu 
437*ddceee07SGeorge Liu inline void
438*ddceee07SGeorge Liu     getEfficiencyPercent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
439*ddceee07SGeorge Liu {
440*ddceee07SGeorge Liu     constexpr std::array<std::string_view, 1> efficiencyIntf = {
441*ddceee07SGeorge Liu         "xyz.openbmc_project.Control.PowerSupplyAttributes"};
442*ddceee07SGeorge Liu 
443*ddceee07SGeorge Liu     dbus::utility::getSubTree(
444*ddceee07SGeorge Liu         "/xyz/openbmc_project", 0, efficiencyIntf,
445*ddceee07SGeorge Liu         [asyncResp](const boost::system::error_code& ec,
446*ddceee07SGeorge Liu                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
447*ddceee07SGeorge Liu         handlePowerSupplyAttributesSubTreeResponse(asyncResp, ec, subtree);
448*ddceee07SGeorge Liu         });
449*ddceee07SGeorge Liu }
450*ddceee07SGeorge Liu 
45144845e5fSGeorge Liu inline void
45200ef5dc6SGeorge Liu     doPowerSupplyGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
45300ef5dc6SGeorge Liu                      const std::string& chassisId,
45400ef5dc6SGeorge Liu                      const std::string& powerSupplyId,
45500ef5dc6SGeorge Liu                      const std::optional<std::string>& validChassisPath)
45600ef5dc6SGeorge Liu {
45700ef5dc6SGeorge Liu     if (!validChassisPath)
45800ef5dc6SGeorge Liu     {
45900ef5dc6SGeorge Liu         messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
46000ef5dc6SGeorge Liu         return;
46100ef5dc6SGeorge Liu     }
46200ef5dc6SGeorge Liu 
46300ef5dc6SGeorge Liu     // Get the correct Path and Service that match the input parameters
46400ef5dc6SGeorge Liu     getValidPowerSupplyPath(asyncResp, *validChassisPath, powerSupplyId,
46534dfcb94SGeorge Liu                             [asyncResp, chassisId, powerSupplyId](
46634dfcb94SGeorge Liu                                 const std::string& powerSupplyPath) {
46700ef5dc6SGeorge Liu         asyncResp->res.addHeader(
46800ef5dc6SGeorge Liu             boost::beast::http::field::link,
46900ef5dc6SGeorge Liu             "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
47000ef5dc6SGeorge Liu         asyncResp->res.jsonValue["@odata.type"] =
47100ef5dc6SGeorge Liu             "#PowerSupply.v1_5_0.PowerSupply";
47200ef5dc6SGeorge Liu         asyncResp->res.jsonValue["Name"] = "Power Supply";
47300ef5dc6SGeorge Liu         asyncResp->res.jsonValue["Id"] = powerSupplyId;
47400ef5dc6SGeorge Liu         asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
47500ef5dc6SGeorge Liu             "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
47600ef5dc6SGeorge Liu             powerSupplyId);
47734dfcb94SGeorge Liu 
47834dfcb94SGeorge Liu         asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
47934dfcb94SGeorge Liu         asyncResp->res.jsonValue["Status"]["Health"] = "OK";
48034dfcb94SGeorge Liu 
48134dfcb94SGeorge Liu         dbus::utility::getDbusObject(
482788fe6cfSLakshmi Yadlapati             powerSupplyPath, powerSupplyInterface,
48334dfcb94SGeorge Liu             [asyncResp,
48434dfcb94SGeorge Liu              powerSupplyPath](const boost::system::error_code& ec,
48534dfcb94SGeorge Liu                               const dbus::utility::MapperGetObject& object) {
48634dfcb94SGeorge Liu             if (ec || object.empty())
48734dfcb94SGeorge Liu             {
48834dfcb94SGeorge Liu                 messages::internalError(asyncResp->res);
48934dfcb94SGeorge Liu                 return;
49034dfcb94SGeorge Liu             }
49134dfcb94SGeorge Liu 
49234dfcb94SGeorge Liu             getPowerSupplyState(asyncResp, object.begin()->first,
49334dfcb94SGeorge Liu                                 powerSupplyPath);
49434dfcb94SGeorge Liu             getPowerSupplyHealth(asyncResp, object.begin()->first,
49534dfcb94SGeorge Liu                                  powerSupplyPath);
4962b45fb3bSGeorge Liu             getPowerSupplyAsset(asyncResp, object.begin()->first,
4972b45fb3bSGeorge Liu                                 powerSupplyPath);
498a0dba87bSGeorge Liu             getPowerSupplyFirmwareVersion(asyncResp, object.begin()->first,
499a0dba87bSGeorge Liu                                           powerSupplyPath);
50044845e5fSGeorge Liu             getPowerSupplyLocation(asyncResp, object.begin()->first,
50144845e5fSGeorge Liu                                    powerSupplyPath);
50234dfcb94SGeorge Liu             });
503*ddceee07SGeorge Liu 
504*ddceee07SGeorge Liu         getEfficiencyPercent(asyncResp);
50500ef5dc6SGeorge Liu     });
50600ef5dc6SGeorge Liu }
50700ef5dc6SGeorge Liu 
50800ef5dc6SGeorge Liu inline void
50900ef5dc6SGeorge Liu     handlePowerSupplyHead(App& app, const crow::Request& req,
51000ef5dc6SGeorge Liu                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
51100ef5dc6SGeorge Liu                           const std::string& chassisId,
51200ef5dc6SGeorge Liu                           const std::string& powerSupplyId)
51300ef5dc6SGeorge Liu {
51400ef5dc6SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
51500ef5dc6SGeorge Liu     {
51600ef5dc6SGeorge Liu         return;
51700ef5dc6SGeorge Liu     }
51800ef5dc6SGeorge Liu 
51900ef5dc6SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
52000ef5dc6SGeorge Liu         asyncResp, chassisId,
52100ef5dc6SGeorge Liu         [asyncResp, chassisId,
52200ef5dc6SGeorge Liu          powerSupplyId](const std::optional<std::string>& validChassisPath) {
52300ef5dc6SGeorge Liu         if (!validChassisPath)
52400ef5dc6SGeorge Liu         {
52500ef5dc6SGeorge Liu             messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
52600ef5dc6SGeorge Liu             return;
52700ef5dc6SGeorge Liu         }
52800ef5dc6SGeorge Liu 
52900ef5dc6SGeorge Liu         // Get the correct Path and Service that match the input parameters
53000ef5dc6SGeorge Liu         getValidPowerSupplyPath(asyncResp, *validChassisPath, powerSupplyId,
53134dfcb94SGeorge Liu                                 [asyncResp](const std::string&) {
53200ef5dc6SGeorge Liu             asyncResp->res.addHeader(
53300ef5dc6SGeorge Liu                 boost::beast::http::field::link,
53400ef5dc6SGeorge Liu                 "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
53500ef5dc6SGeorge Liu         });
53600ef5dc6SGeorge Liu         });
53700ef5dc6SGeorge Liu }
53800ef5dc6SGeorge Liu 
53900ef5dc6SGeorge Liu inline void
54000ef5dc6SGeorge Liu     handlePowerSupplyGet(App& app, const crow::Request& req,
54100ef5dc6SGeorge Liu                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
54200ef5dc6SGeorge Liu                          const std::string& chassisId,
54300ef5dc6SGeorge Liu                          const std::string& powerSupplyId)
54400ef5dc6SGeorge Liu {
54500ef5dc6SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
54600ef5dc6SGeorge Liu     {
54700ef5dc6SGeorge Liu         return;
54800ef5dc6SGeorge Liu     }
54900ef5dc6SGeorge Liu 
55000ef5dc6SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
55100ef5dc6SGeorge Liu         asyncResp, chassisId,
55200ef5dc6SGeorge Liu         std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId));
55300ef5dc6SGeorge Liu }
55400ef5dc6SGeorge Liu 
55500ef5dc6SGeorge Liu inline void requestRoutesPowerSupply(App& app)
55600ef5dc6SGeorge Liu {
55700ef5dc6SGeorge Liu     BMCWEB_ROUTE(
55800ef5dc6SGeorge Liu         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
55900ef5dc6SGeorge Liu         .privileges(redfish::privileges::headPowerSupply)
56000ef5dc6SGeorge Liu         .methods(boost::beast::http::verb::head)(
56100ef5dc6SGeorge Liu             std::bind_front(handlePowerSupplyHead, std::ref(app)));
56200ef5dc6SGeorge Liu 
56300ef5dc6SGeorge Liu     BMCWEB_ROUTE(
56400ef5dc6SGeorge Liu         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
56500ef5dc6SGeorge Liu         .privileges(redfish::privileges::getPowerSupply)
56600ef5dc6SGeorge Liu         .methods(boost::beast::http::verb::get)(
56700ef5dc6SGeorge Liu             std::bind_front(handlePowerSupplyGet, std::ref(app)));
56800ef5dc6SGeorge Liu }
56900ef5dc6SGeorge Liu 
570a7210020SGeorge Liu } // namespace redfish
571