xref: /openbmc/bmcweb/features/redfish/lib/power_supply.hpp (revision bd79bce8c3f1deb1fb2773868b9ece25233cf27b)
1a7210020SGeorge Liu #pragma once
2a7210020SGeorge Liu 
3a7210020SGeorge Liu #include "app.hpp"
4a7210020SGeorge Liu #include "dbus_utility.hpp"
5539d8c6bSEd Tanous #include "generated/enums/resource.hpp"
6a7210020SGeorge Liu #include "query.hpp"
7a7210020SGeorge Liu #include "registries/privilege_registry.hpp"
8a7210020SGeorge Liu #include "utils/chassis_utils.hpp"
92b45fb3bSGeorge Liu #include "utils/dbus_utils.hpp"
102b45fb3bSGeorge Liu #include "utils/json_utils.hpp"
11a7210020SGeorge Liu 
1234dfcb94SGeorge Liu #include <boost/system/error_code.hpp>
13ef4c65b7SEd Tanous #include <boost/url/format.hpp>
14ef4c65b7SEd Tanous 
15a7210020SGeorge Liu #include <memory>
16a7210020SGeorge Liu #include <optional>
17a7210020SGeorge Liu #include <string>
18a7210020SGeorge Liu 
19a7210020SGeorge Liu namespace redfish
20a7210020SGeorge Liu {
21a7210020SGeorge Liu 
22788fe6cfSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> powerSupplyInterface = {
23788fe6cfSLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PowerSupply"};
24788fe6cfSLakshmi Yadlapati 
25788fe6cfSLakshmi Yadlapati inline void updatePowerSupplyList(
26788fe6cfSLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2700ef5dc6SGeorge Liu     const std::string& chassisId,
28788fe6cfSLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& powerSupplyPaths)
29788fe6cfSLakshmi Yadlapati {
30788fe6cfSLakshmi Yadlapati     nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"];
31788fe6cfSLakshmi Yadlapati     for (const std::string& powerSupplyPath : powerSupplyPaths)
32a7210020SGeorge Liu     {
3300ef5dc6SGeorge Liu         std::string powerSupplyName =
3400ef5dc6SGeorge Liu             sdbusplus::message::object_path(powerSupplyPath).filename();
3500ef5dc6SGeorge Liu         if (powerSupplyName.empty())
3600ef5dc6SGeorge Liu         {
37788fe6cfSLakshmi Yadlapati             continue;
3800ef5dc6SGeorge Liu         }
3900ef5dc6SGeorge Liu 
4000ef5dc6SGeorge Liu         nlohmann::json item = nlohmann::json::object();
4100ef5dc6SGeorge Liu         item["@odata.id"] = boost::urls::format(
4200ef5dc6SGeorge Liu             "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
4300ef5dc6SGeorge Liu             powerSupplyName);
4400ef5dc6SGeorge Liu 
4500ef5dc6SGeorge Liu         powerSupplyList.emplace_back(std::move(item));
46788fe6cfSLakshmi Yadlapati     }
4700ef5dc6SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size();
48a7210020SGeorge Liu }
49a7210020SGeorge Liu 
50a7210020SGeorge Liu inline void
51a7210020SGeorge Liu     doPowerSupplyCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
52a7210020SGeorge Liu                             const std::string& chassisId,
53a7210020SGeorge Liu                             const std::optional<std::string>& validChassisPath)
54a7210020SGeorge Liu {
55a7210020SGeorge Liu     if (!validChassisPath)
56a7210020SGeorge Liu     {
57a7210020SGeorge Liu         messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
58a7210020SGeorge Liu         return;
59a7210020SGeorge Liu     }
60a7210020SGeorge Liu 
61a7210020SGeorge Liu     asyncResp->res.addHeader(
62a7210020SGeorge Liu         boost::beast::http::field::link,
63a7210020SGeorge Liu         "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
64a7210020SGeorge Liu     asyncResp->res.jsonValue["@odata.type"] =
65a7210020SGeorge Liu         "#PowerSupplyCollection.PowerSupplyCollection";
66a7210020SGeorge Liu     asyncResp->res.jsonValue["Name"] = "Power Supply Collection";
67ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
68ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId);
69a7210020SGeorge Liu     asyncResp->res.jsonValue["Description"] =
70a7210020SGeorge Liu         "The collection of PowerSupply resource instances.";
717a2bb2c9SGeorge Liu     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
727a2bb2c9SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = 0;
73a7210020SGeorge Liu 
74a7210020SGeorge Liu     std::string powerPath = *validChassisPath + "/powered_by";
75788fe6cfSLakshmi Yadlapati     dbus::utility::getAssociatedSubTreePaths(
76788fe6cfSLakshmi Yadlapati         powerPath,
77788fe6cfSLakshmi Yadlapati         sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
78788fe6cfSLakshmi Yadlapati         powerSupplyInterface,
79788fe6cfSLakshmi Yadlapati         [asyncResp, chassisId](
80a7210020SGeorge Liu             const boost::system::error_code& ec,
81788fe6cfSLakshmi Yadlapati             const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
82a7210020SGeorge Liu             if (ec)
83a7210020SGeorge Liu             {
84a7210020SGeorge Liu                 if (ec.value() != EBADR)
85a7210020SGeorge Liu                 {
8662598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
87a7210020SGeorge Liu                     messages::internalError(asyncResp->res);
88a7210020SGeorge Liu                 }
89a7210020SGeorge Liu                 return;
90a7210020SGeorge Liu             }
91a7210020SGeorge Liu 
92788fe6cfSLakshmi Yadlapati             updatePowerSupplyList(asyncResp, chassisId, subtreePaths);
93a7210020SGeorge Liu         });
94a7210020SGeorge Liu }
95a7210020SGeorge Liu 
96a7210020SGeorge Liu inline void handlePowerSupplyCollectionHead(
97a7210020SGeorge Liu     App& app, const crow::Request& req,
98a7210020SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
99a7210020SGeorge Liu     const std::string& chassisId)
100a7210020SGeorge Liu {
101a7210020SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
102a7210020SGeorge Liu     {
103a7210020SGeorge Liu         return;
104a7210020SGeorge Liu     }
105a7210020SGeorge Liu 
106a7210020SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
107a7210020SGeorge Liu         asyncResp, chassisId,
108a7210020SGeorge Liu         [asyncResp,
109a7210020SGeorge Liu          chassisId](const std::optional<std::string>& validChassisPath) {
110a7210020SGeorge Liu             if (!validChassisPath)
111a7210020SGeorge Liu             {
112*bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res, "Chassis",
113*bd79bce8SPatrick Williams                                            chassisId);
114a7210020SGeorge Liu                 return;
115a7210020SGeorge Liu             }
116a7210020SGeorge Liu             asyncResp->res.addHeader(
117a7210020SGeorge Liu                 boost::beast::http::field::link,
118a7210020SGeorge Liu                 "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
119a7210020SGeorge Liu         });
120a7210020SGeorge Liu }
121a7210020SGeorge Liu 
122a7210020SGeorge Liu inline void handlePowerSupplyCollectionGet(
123a7210020SGeorge Liu     App& app, const crow::Request& req,
124a7210020SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
125a7210020SGeorge Liu     const std::string& chassisId)
126a7210020SGeorge Liu {
127a7210020SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
128a7210020SGeorge Liu     {
129a7210020SGeorge Liu         return;
130a7210020SGeorge Liu     }
131a7210020SGeorge Liu 
132a7210020SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
133a7210020SGeorge Liu         asyncResp, chassisId,
134a7210020SGeorge Liu         std::bind_front(doPowerSupplyCollection, asyncResp, chassisId));
135a7210020SGeorge Liu }
136a7210020SGeorge Liu 
137a7210020SGeorge Liu inline void requestRoutesPowerSupplyCollection(App& app)
138a7210020SGeorge Liu {
139a7210020SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
140a7210020SGeorge Liu         .privileges(redfish::privileges::headPowerSupplyCollection)
141a7210020SGeorge Liu         .methods(boost::beast::http::verb::head)(
142a7210020SGeorge Liu             std::bind_front(handlePowerSupplyCollectionHead, std::ref(app)));
143a7210020SGeorge Liu 
144a7210020SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
145a7210020SGeorge Liu         .privileges(redfish::privileges::getPowerSupplyCollection)
146a7210020SGeorge Liu         .methods(boost::beast::http::verb::get)(
147a7210020SGeorge Liu             std::bind_front(handlePowerSupplyCollectionGet, std::ref(app)));
148a7210020SGeorge Liu }
149a7210020SGeorge Liu 
15000ef5dc6SGeorge Liu inline bool checkPowerSupplyId(const std::string& powerSupplyPath,
15100ef5dc6SGeorge Liu                                const std::string& powerSupplyId)
15200ef5dc6SGeorge Liu {
15300ef5dc6SGeorge Liu     std::string powerSupplyName =
15400ef5dc6SGeorge Liu         sdbusplus::message::object_path(powerSupplyPath).filename();
15500ef5dc6SGeorge Liu 
15600ef5dc6SGeorge Liu     return !(powerSupplyName.empty() || powerSupplyName != powerSupplyId);
15700ef5dc6SGeorge Liu }
15800ef5dc6SGeorge Liu 
15934dfcb94SGeorge Liu inline void getValidPowerSupplyPath(
16034dfcb94SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
16134dfcb94SGeorge Liu     const std::string& validChassisPath, const std::string& powerSupplyId,
16234dfcb94SGeorge Liu     std::function<void(const std::string& powerSupplyPath)>&& callback)
16300ef5dc6SGeorge Liu {
16400ef5dc6SGeorge Liu     std::string powerPath = validChassisPath + "/powered_by";
165788fe6cfSLakshmi Yadlapati     dbus::utility::getAssociatedSubTreePaths(
166788fe6cfSLakshmi Yadlapati         powerPath,
167788fe6cfSLakshmi Yadlapati         sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
168788fe6cfSLakshmi Yadlapati         powerSupplyInterface,
169788fe6cfSLakshmi Yadlapati         [asyncResp, powerSupplyId, callback{std::move(callback)}](
17000ef5dc6SGeorge Liu             const boost::system::error_code& ec,
171788fe6cfSLakshmi Yadlapati             const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
17200ef5dc6SGeorge Liu             if (ec)
17300ef5dc6SGeorge Liu             {
17400ef5dc6SGeorge Liu                 if (ec.value() != EBADR)
17500ef5dc6SGeorge Liu                 {
17662598e31SEd Tanous                     BMCWEB_LOG_ERROR(
17762598e31SEd Tanous                         "DBUS response error for getAssociatedSubTreePaths{}",
17862598e31SEd Tanous                         ec.value());
17900ef5dc6SGeorge Liu                     messages::internalError(asyncResp->res);
18000ef5dc6SGeorge Liu                     return;
18100ef5dc6SGeorge Liu                 }
18200ef5dc6SGeorge Liu                 messages::resourceNotFound(asyncResp->res, "PowerSupplies",
18300ef5dc6SGeorge Liu                                            powerSupplyId);
18400ef5dc6SGeorge Liu                 return;
18500ef5dc6SGeorge Liu             }
18600ef5dc6SGeorge Liu 
187788fe6cfSLakshmi Yadlapati             for (const std::string& path : subtreePaths)
18800ef5dc6SGeorge Liu             {
189788fe6cfSLakshmi Yadlapati                 if (checkPowerSupplyId(path, powerSupplyId))
19000ef5dc6SGeorge Liu                 {
191788fe6cfSLakshmi Yadlapati                     callback(path);
19200ef5dc6SGeorge Liu                     return;
19300ef5dc6SGeorge Liu                 }
19400ef5dc6SGeorge Liu             }
19500ef5dc6SGeorge Liu 
196788fe6cfSLakshmi Yadlapati             if (!subtreePaths.empty())
19700ef5dc6SGeorge Liu             {
19862598e31SEd Tanous                 BMCWEB_LOG_WARNING("Power supply not found: {}", powerSupplyId);
19900ef5dc6SGeorge Liu                 messages::resourceNotFound(asyncResp->res, "PowerSupplies",
20000ef5dc6SGeorge Liu                                            powerSupplyId);
20100ef5dc6SGeorge Liu                 return;
20200ef5dc6SGeorge Liu             }
20300ef5dc6SGeorge Liu         });
20400ef5dc6SGeorge Liu }
20500ef5dc6SGeorge Liu 
20600ef5dc6SGeorge Liu inline void
20734dfcb94SGeorge Liu     getPowerSupplyState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
20834dfcb94SGeorge Liu                         const std::string& service, const std::string& path)
20934dfcb94SGeorge Liu {
21034dfcb94SGeorge Liu     sdbusplus::asio::getProperty<bool>(
21134dfcb94SGeorge Liu         *crow::connections::systemBus, service, path,
21234dfcb94SGeorge Liu         "xyz.openbmc_project.Inventory.Item", "Present",
21334dfcb94SGeorge Liu         [asyncResp](const boost::system::error_code& ec, const bool value) {
21434dfcb94SGeorge Liu             if (ec)
21534dfcb94SGeorge Liu             {
21634dfcb94SGeorge Liu                 if (ec.value() != EBADR)
21734dfcb94SGeorge Liu                 {
21862598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for State {}",
21962598e31SEd Tanous                                      ec.value());
22034dfcb94SGeorge Liu                     messages::internalError(asyncResp->res);
22134dfcb94SGeorge Liu                 }
22234dfcb94SGeorge Liu                 return;
22334dfcb94SGeorge Liu             }
22434dfcb94SGeorge Liu 
22534dfcb94SGeorge Liu             if (!value)
22634dfcb94SGeorge Liu             {
227539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
228539d8c6bSEd Tanous                     resource::State::Absent;
22934dfcb94SGeorge Liu             }
23034dfcb94SGeorge Liu         });
23134dfcb94SGeorge Liu }
23234dfcb94SGeorge Liu 
23334dfcb94SGeorge Liu inline void
23434dfcb94SGeorge Liu     getPowerSupplyHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
23534dfcb94SGeorge Liu                          const std::string& service, const std::string& path)
23634dfcb94SGeorge Liu {
23734dfcb94SGeorge Liu     sdbusplus::asio::getProperty<bool>(
23834dfcb94SGeorge Liu         *crow::connections::systemBus, service, path,
23934dfcb94SGeorge Liu         "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
24034dfcb94SGeorge Liu         [asyncResp](const boost::system::error_code& ec, const bool value) {
24134dfcb94SGeorge Liu             if (ec)
24234dfcb94SGeorge Liu             {
24334dfcb94SGeorge Liu                 if (ec.value() != EBADR)
24434dfcb94SGeorge Liu                 {
24562598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Health {}",
24662598e31SEd Tanous                                      ec.value());
24734dfcb94SGeorge Liu                     messages::internalError(asyncResp->res);
24834dfcb94SGeorge Liu                 }
24934dfcb94SGeorge Liu                 return;
25034dfcb94SGeorge Liu             }
25134dfcb94SGeorge Liu 
25234dfcb94SGeorge Liu             if (!value)
25334dfcb94SGeorge Liu             {
254539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["Health"] =
255539d8c6bSEd Tanous                     resource::Health::Critical;
25634dfcb94SGeorge Liu             }
25734dfcb94SGeorge Liu         });
25834dfcb94SGeorge Liu }
25934dfcb94SGeorge Liu 
26034dfcb94SGeorge Liu inline void
2612b45fb3bSGeorge Liu     getPowerSupplyAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2622b45fb3bSGeorge Liu                         const std::string& service, const std::string& path)
2632b45fb3bSGeorge Liu {
2642b45fb3bSGeorge Liu     sdbusplus::asio::getAllProperties(
2652b45fb3bSGeorge Liu         *crow::connections::systemBus, service, path,
2662b45fb3bSGeorge Liu         "xyz.openbmc_project.Inventory.Decorator.Asset",
2672b45fb3bSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
2682b45fb3bSGeorge Liu                     const dbus::utility::DBusPropertiesMap& propertiesList) {
2692b45fb3bSGeorge Liu             if (ec)
2702b45fb3bSGeorge Liu             {
2712b45fb3bSGeorge Liu                 if (ec.value() != EBADR)
2722b45fb3bSGeorge Liu                 {
27362598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Asset {}",
27462598e31SEd Tanous                                      ec.value());
2752b45fb3bSGeorge Liu                     messages::internalError(asyncResp->res);
2762b45fb3bSGeorge Liu                 }
2772b45fb3bSGeorge Liu                 return;
2782b45fb3bSGeorge Liu             }
2792b45fb3bSGeorge Liu 
2802b45fb3bSGeorge Liu             const std::string* partNumber = nullptr;
2812b45fb3bSGeorge Liu             const std::string* serialNumber = nullptr;
2822b45fb3bSGeorge Liu             const std::string* manufacturer = nullptr;
2832b45fb3bSGeorge Liu             const std::string* model = nullptr;
2842b45fb3bSGeorge Liu             const std::string* sparePartNumber = nullptr;
2852b45fb3bSGeorge Liu 
2862b45fb3bSGeorge Liu             const bool success = sdbusplus::unpackPropertiesNoThrow(
2872b45fb3bSGeorge Liu                 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
2882b45fb3bSGeorge Liu                 partNumber, "SerialNumber", serialNumber, "Manufacturer",
289*bd79bce8SPatrick Williams                 manufacturer, "Model", model, "SparePartNumber",
290*bd79bce8SPatrick Williams                 sparePartNumber);
2912b45fb3bSGeorge Liu 
2922b45fb3bSGeorge Liu             if (!success)
2932b45fb3bSGeorge Liu             {
2942b45fb3bSGeorge Liu                 messages::internalError(asyncResp->res);
2952b45fb3bSGeorge Liu                 return;
2962b45fb3bSGeorge Liu             }
2972b45fb3bSGeorge Liu 
2982b45fb3bSGeorge Liu             if (partNumber != nullptr)
2992b45fb3bSGeorge Liu             {
3002b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
3012b45fb3bSGeorge Liu             }
3022b45fb3bSGeorge Liu 
3032b45fb3bSGeorge Liu             if (serialNumber != nullptr)
3042b45fb3bSGeorge Liu             {
3052b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
3062b45fb3bSGeorge Liu             }
3072b45fb3bSGeorge Liu 
3082b45fb3bSGeorge Liu             if (manufacturer != nullptr)
3092b45fb3bSGeorge Liu             {
3102b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
3112b45fb3bSGeorge Liu             }
3122b45fb3bSGeorge Liu 
3132b45fb3bSGeorge Liu             if (model != nullptr)
3142b45fb3bSGeorge Liu             {
3152b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["Model"] = *model;
3162b45fb3bSGeorge Liu             }
3172b45fb3bSGeorge Liu 
3182b45fb3bSGeorge Liu             // SparePartNumber is optional on D-Bus so skip if it is empty
3192b45fb3bSGeorge Liu             if (sparePartNumber != nullptr && !sparePartNumber->empty())
3202b45fb3bSGeorge Liu             {
3212b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
3222b45fb3bSGeorge Liu             }
3232b45fb3bSGeorge Liu         });
3242b45fb3bSGeorge Liu }
3252b45fb3bSGeorge Liu 
326a0dba87bSGeorge Liu inline void getPowerSupplyFirmwareVersion(
327a0dba87bSGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
328a0dba87bSGeorge Liu     const std::string& service, const std::string& path)
329a0dba87bSGeorge Liu {
330a0dba87bSGeorge Liu     sdbusplus::asio::getProperty<std::string>(
331a0dba87bSGeorge Liu         *crow::connections::systemBus, service, path,
332a0dba87bSGeorge Liu         "xyz.openbmc_project.Software.Version", "Version",
333a0dba87bSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
334a0dba87bSGeorge Liu                     const std::string& value) {
335a0dba87bSGeorge Liu             if (ec)
336a0dba87bSGeorge Liu             {
337a0dba87bSGeorge Liu                 if (ec.value() != EBADR)
338a0dba87bSGeorge Liu                 {
339*bd79bce8SPatrick Williams                     BMCWEB_LOG_ERROR(
340*bd79bce8SPatrick Williams                         "DBUS response error for FirmwareVersion {}",
34162598e31SEd Tanous                         ec.value());
342a0dba87bSGeorge Liu                     messages::internalError(asyncResp->res);
343a0dba87bSGeorge Liu                 }
344a0dba87bSGeorge Liu                 return;
345a0dba87bSGeorge Liu             }
346a0dba87bSGeorge Liu             asyncResp->res.jsonValue["FirmwareVersion"] = value;
347a0dba87bSGeorge Liu         });
348a0dba87bSGeorge Liu }
349a0dba87bSGeorge Liu 
3502b45fb3bSGeorge Liu inline void
35144845e5fSGeorge Liu     getPowerSupplyLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
35244845e5fSGeorge Liu                            const std::string& service, const std::string& path)
35344845e5fSGeorge Liu {
35444845e5fSGeorge Liu     sdbusplus::asio::getProperty<std::string>(
35544845e5fSGeorge Liu         *crow::connections::systemBus, service, path,
35644845e5fSGeorge Liu         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
35744845e5fSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
35844845e5fSGeorge Liu                     const std::string& value) {
35944845e5fSGeorge Liu             if (ec)
36044845e5fSGeorge Liu             {
36144845e5fSGeorge Liu                 if (ec.value() != EBADR)
36244845e5fSGeorge Liu                 {
36362598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Location {}",
36462598e31SEd Tanous                                      ec.value());
36544845e5fSGeorge Liu                     messages::internalError(asyncResp->res);
36644845e5fSGeorge Liu                 }
36744845e5fSGeorge Liu                 return;
36844845e5fSGeorge Liu             }
369*bd79bce8SPatrick Williams             asyncResp->res
370*bd79bce8SPatrick Williams                 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = value;
37144845e5fSGeorge Liu         });
37244845e5fSGeorge Liu }
37344845e5fSGeorge Liu 
374ddceee07SGeorge Liu inline void handleGetEfficiencyResponse(
375ddceee07SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
376ddceee07SGeorge Liu     const boost::system::error_code& ec, uint32_t value)
377ddceee07SGeorge Liu {
378ddceee07SGeorge Liu     if (ec)
379ddceee07SGeorge Liu     {
380ddceee07SGeorge Liu         if (ec.value() != EBADR)
381ddceee07SGeorge Liu         {
38262598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for DeratingFactor {}",
38362598e31SEd Tanous                              ec.value());
384ddceee07SGeorge Liu             messages::internalError(asyncResp->res);
385ddceee07SGeorge Liu         }
386ddceee07SGeorge Liu         return;
387ddceee07SGeorge Liu     }
388ddceee07SGeorge Liu     // The PDI default value is 0, if it hasn't been set leave off
389ddceee07SGeorge Liu     if (value == 0)
390ddceee07SGeorge Liu     {
391ddceee07SGeorge Liu         return;
392ddceee07SGeorge Liu     }
393ddceee07SGeorge Liu 
394ddceee07SGeorge Liu     nlohmann::json::array_t efficiencyRatings;
395ddceee07SGeorge Liu     nlohmann::json::object_t efficiencyPercent;
396ddceee07SGeorge Liu     efficiencyPercent["EfficiencyPercent"] = value;
397ddceee07SGeorge Liu     efficiencyRatings.emplace_back(std::move(efficiencyPercent));
398ddceee07SGeorge Liu     asyncResp->res.jsonValue["EfficiencyRatings"] =
399ddceee07SGeorge Liu         std::move(efficiencyRatings);
400ddceee07SGeorge Liu }
401ddceee07SGeorge Liu 
402ddceee07SGeorge Liu inline void handlePowerSupplyAttributesSubTreeResponse(
403ddceee07SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
404ddceee07SGeorge Liu     const boost::system::error_code& ec,
405ddceee07SGeorge Liu     const dbus::utility::MapperGetSubTreeResponse& subtree)
406ddceee07SGeorge Liu {
407ddceee07SGeorge Liu     if (ec)
408ddceee07SGeorge Liu     {
409ddceee07SGeorge Liu         if (ec.value() != EBADR)
410ddceee07SGeorge Liu         {
41162598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for EfficiencyPercent {}",
41262598e31SEd Tanous                              ec.value());
413ddceee07SGeorge Liu             messages::internalError(asyncResp->res);
414ddceee07SGeorge Liu         }
415ddceee07SGeorge Liu         return;
416ddceee07SGeorge Liu     }
417ddceee07SGeorge Liu 
418ddceee07SGeorge Liu     if (subtree.empty())
419ddceee07SGeorge Liu     {
42062598e31SEd Tanous         BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
421ddceee07SGeorge Liu         return;
422ddceee07SGeorge Liu     }
423ddceee07SGeorge Liu 
424ddceee07SGeorge Liu     if (subtree.size() != 1)
425ddceee07SGeorge Liu     {
42662598e31SEd Tanous         BMCWEB_LOG_ERROR(
42762598e31SEd Tanous             "Unexpected number of paths returned by getSubTree: {}",
42862598e31SEd Tanous             subtree.size());
429ddceee07SGeorge Liu         messages::internalError(asyncResp->res);
430ddceee07SGeorge Liu         return;
431ddceee07SGeorge Liu     }
432ddceee07SGeorge Liu 
433ddceee07SGeorge Liu     const auto& [path, serviceMap] = *subtree.begin();
434ddceee07SGeorge Liu     const auto& [service, interfaces] = *serviceMap.begin();
435ddceee07SGeorge Liu     sdbusplus::asio::getProperty<uint32_t>(
436ddceee07SGeorge Liu         *crow::connections::systemBus, service, path,
437ddceee07SGeorge Liu         "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
438ddceee07SGeorge Liu         [asyncResp](const boost::system::error_code& ec1, uint32_t value) {
439ddceee07SGeorge Liu             handleGetEfficiencyResponse(asyncResp, ec1, value);
440ddceee07SGeorge Liu         });
441ddceee07SGeorge Liu }
442ddceee07SGeorge Liu 
443ddceee07SGeorge Liu inline void
444ddceee07SGeorge Liu     getEfficiencyPercent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
445ddceee07SGeorge Liu {
446ddceee07SGeorge Liu     constexpr std::array<std::string_view, 1> efficiencyIntf = {
447ddceee07SGeorge Liu         "xyz.openbmc_project.Control.PowerSupplyAttributes"};
448ddceee07SGeorge Liu 
449ddceee07SGeorge Liu     dbus::utility::getSubTree(
450ddceee07SGeorge Liu         "/xyz/openbmc_project", 0, efficiencyIntf,
451ddceee07SGeorge Liu         [asyncResp](const boost::system::error_code& ec,
452ddceee07SGeorge Liu                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
453ddceee07SGeorge Liu             handlePowerSupplyAttributesSubTreeResponse(asyncResp, ec, subtree);
454ddceee07SGeorge Liu         });
455ddceee07SGeorge Liu }
456ddceee07SGeorge Liu 
457*bd79bce8SPatrick Williams inline void doPowerSupplyGet(
458*bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
459*bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& powerSupplyId,
46000ef5dc6SGeorge Liu     const std::optional<std::string>& validChassisPath)
46100ef5dc6SGeorge Liu {
46200ef5dc6SGeorge Liu     if (!validChassisPath)
46300ef5dc6SGeorge Liu     {
46400ef5dc6SGeorge Liu         messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
46500ef5dc6SGeorge Liu         return;
46600ef5dc6SGeorge Liu     }
46700ef5dc6SGeorge Liu 
46800ef5dc6SGeorge Liu     // Get the correct Path and Service that match the input parameters
469*bd79bce8SPatrick Williams     getValidPowerSupplyPath(
470*bd79bce8SPatrick Williams         asyncResp, *validChassisPath, powerSupplyId,
471*bd79bce8SPatrick Williams         [asyncResp, chassisId,
472*bd79bce8SPatrick Williams          powerSupplyId](const std::string& powerSupplyPath) {
47300ef5dc6SGeorge Liu             asyncResp->res.addHeader(
47400ef5dc6SGeorge Liu                 boost::beast::http::field::link,
47500ef5dc6SGeorge Liu                 "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
47600ef5dc6SGeorge Liu             asyncResp->res.jsonValue["@odata.type"] =
47700ef5dc6SGeorge Liu                 "#PowerSupply.v1_5_0.PowerSupply";
47800ef5dc6SGeorge Liu             asyncResp->res.jsonValue["Name"] = "Power Supply";
47900ef5dc6SGeorge Liu             asyncResp->res.jsonValue["Id"] = powerSupplyId;
48000ef5dc6SGeorge Liu             asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
481*bd79bce8SPatrick Williams                 "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}",
482*bd79bce8SPatrick Williams                 chassisId, powerSupplyId);
48334dfcb94SGeorge Liu 
484*bd79bce8SPatrick Williams             asyncResp->res.jsonValue["Status"]["State"] =
485*bd79bce8SPatrick Williams                 resource::State::Enabled;
486539d8c6bSEd Tanous             asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
48734dfcb94SGeorge Liu 
48834dfcb94SGeorge Liu             dbus::utility::getDbusObject(
489788fe6cfSLakshmi Yadlapati                 powerSupplyPath, powerSupplyInterface,
490*bd79bce8SPatrick Williams                 [asyncResp, powerSupplyPath](
491*bd79bce8SPatrick Williams                     const boost::system::error_code& ec,
49234dfcb94SGeorge Liu                     const dbus::utility::MapperGetObject& object) {
49334dfcb94SGeorge Liu                     if (ec || object.empty())
49434dfcb94SGeorge Liu                     {
49534dfcb94SGeorge Liu                         messages::internalError(asyncResp->res);
49634dfcb94SGeorge Liu                         return;
49734dfcb94SGeorge Liu                     }
49834dfcb94SGeorge Liu 
49934dfcb94SGeorge Liu                     getPowerSupplyState(asyncResp, object.begin()->first,
50034dfcb94SGeorge Liu                                         powerSupplyPath);
50134dfcb94SGeorge Liu                     getPowerSupplyHealth(asyncResp, object.begin()->first,
50234dfcb94SGeorge Liu                                          powerSupplyPath);
5032b45fb3bSGeorge Liu                     getPowerSupplyAsset(asyncResp, object.begin()->first,
5042b45fb3bSGeorge Liu                                         powerSupplyPath);
505*bd79bce8SPatrick Williams                     getPowerSupplyFirmwareVersion(
506*bd79bce8SPatrick Williams                         asyncResp, object.begin()->first, powerSupplyPath);
50744845e5fSGeorge Liu                     getPowerSupplyLocation(asyncResp, object.begin()->first,
50844845e5fSGeorge Liu                                            powerSupplyPath);
50934dfcb94SGeorge Liu                 });
510ddceee07SGeorge Liu 
511ddceee07SGeorge Liu             getEfficiencyPercent(asyncResp);
51200ef5dc6SGeorge Liu         });
51300ef5dc6SGeorge Liu }
51400ef5dc6SGeorge Liu 
515*bd79bce8SPatrick Williams inline void handlePowerSupplyHead(
516*bd79bce8SPatrick Williams     App& app, const crow::Request& req,
51700ef5dc6SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
518*bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& powerSupplyId)
51900ef5dc6SGeorge Liu {
52000ef5dc6SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
52100ef5dc6SGeorge Liu     {
52200ef5dc6SGeorge Liu         return;
52300ef5dc6SGeorge Liu     }
52400ef5dc6SGeorge Liu 
52500ef5dc6SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
52600ef5dc6SGeorge Liu         asyncResp, chassisId,
52700ef5dc6SGeorge Liu         [asyncResp, chassisId,
52800ef5dc6SGeorge Liu          powerSupplyId](const std::optional<std::string>& validChassisPath) {
52900ef5dc6SGeorge Liu             if (!validChassisPath)
53000ef5dc6SGeorge Liu             {
531*bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res, "Chassis",
532*bd79bce8SPatrick Williams                                            chassisId);
53300ef5dc6SGeorge Liu                 return;
53400ef5dc6SGeorge Liu             }
53500ef5dc6SGeorge Liu 
53600ef5dc6SGeorge Liu             // Get the correct Path and Service that match the input parameters
537*bd79bce8SPatrick Williams             getValidPowerSupplyPath(
538*bd79bce8SPatrick Williams                 asyncResp, *validChassisPath, powerSupplyId,
53934dfcb94SGeorge Liu                 [asyncResp](const std::string&) {
54000ef5dc6SGeorge Liu                     asyncResp->res.addHeader(
54100ef5dc6SGeorge Liu                         boost::beast::http::field::link,
54200ef5dc6SGeorge Liu                         "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
54300ef5dc6SGeorge Liu                 });
54400ef5dc6SGeorge Liu         });
54500ef5dc6SGeorge Liu }
54600ef5dc6SGeorge Liu 
547*bd79bce8SPatrick Williams inline void handlePowerSupplyGet(
548*bd79bce8SPatrick Williams     App& app, const crow::Request& req,
54900ef5dc6SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
550*bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& powerSupplyId)
55100ef5dc6SGeorge Liu {
55200ef5dc6SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
55300ef5dc6SGeorge Liu     {
55400ef5dc6SGeorge Liu         return;
55500ef5dc6SGeorge Liu     }
55600ef5dc6SGeorge Liu 
55700ef5dc6SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
55800ef5dc6SGeorge Liu         asyncResp, chassisId,
55900ef5dc6SGeorge Liu         std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId));
56000ef5dc6SGeorge Liu }
56100ef5dc6SGeorge Liu 
56200ef5dc6SGeorge Liu inline void requestRoutesPowerSupply(App& app)
56300ef5dc6SGeorge Liu {
56400ef5dc6SGeorge Liu     BMCWEB_ROUTE(
56500ef5dc6SGeorge Liu         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
56600ef5dc6SGeorge Liu         .privileges(redfish::privileges::headPowerSupply)
56700ef5dc6SGeorge Liu         .methods(boost::beast::http::verb::head)(
56800ef5dc6SGeorge Liu             std::bind_front(handlePowerSupplyHead, std::ref(app)));
56900ef5dc6SGeorge Liu 
57000ef5dc6SGeorge Liu     BMCWEB_ROUTE(
57100ef5dc6SGeorge Liu         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
57200ef5dc6SGeorge Liu         .privileges(redfish::privileges::getPowerSupply)
57300ef5dc6SGeorge Liu         .methods(boost::beast::http::verb::get)(
57400ef5dc6SGeorge Liu             std::bind_front(handlePowerSupplyGet, std::ref(app)));
57500ef5dc6SGeorge Liu }
57600ef5dc6SGeorge Liu 
577a7210020SGeorge Liu } // namespace redfish
578