xref: /openbmc/bmcweb/features/redfish/lib/power_supply.hpp (revision b5190062437414f32c3585cbe02093a4cf27f86a)
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"
11*b5190062SHieu Huynh #include "utils/time_utils.hpp"
12a7210020SGeorge Liu 
1334dfcb94SGeorge Liu #include <boost/system/error_code.hpp>
14ef4c65b7SEd Tanous #include <boost/url/format.hpp>
15ef4c65b7SEd Tanous 
16a7210020SGeorge Liu #include <memory>
17a7210020SGeorge Liu #include <optional>
18a7210020SGeorge Liu #include <string>
19a7210020SGeorge Liu 
20a7210020SGeorge Liu namespace redfish
21a7210020SGeorge Liu {
22a7210020SGeorge Liu 
23788fe6cfSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> powerSupplyInterface = {
24788fe6cfSLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PowerSupply"};
25788fe6cfSLakshmi Yadlapati 
26788fe6cfSLakshmi Yadlapati inline void updatePowerSupplyList(
27788fe6cfSLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2800ef5dc6SGeorge Liu     const std::string& chassisId,
29788fe6cfSLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& powerSupplyPaths)
30788fe6cfSLakshmi Yadlapati {
31788fe6cfSLakshmi Yadlapati     nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"];
32788fe6cfSLakshmi Yadlapati     for (const std::string& powerSupplyPath : powerSupplyPaths)
33a7210020SGeorge Liu     {
3400ef5dc6SGeorge Liu         std::string powerSupplyName =
3500ef5dc6SGeorge Liu             sdbusplus::message::object_path(powerSupplyPath).filename();
3600ef5dc6SGeorge Liu         if (powerSupplyName.empty())
3700ef5dc6SGeorge Liu         {
38788fe6cfSLakshmi Yadlapati             continue;
3900ef5dc6SGeorge Liu         }
4000ef5dc6SGeorge Liu 
4100ef5dc6SGeorge Liu         nlohmann::json item = nlohmann::json::object();
4200ef5dc6SGeorge Liu         item["@odata.id"] = boost::urls::format(
4300ef5dc6SGeorge Liu             "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
4400ef5dc6SGeorge Liu             powerSupplyName);
4500ef5dc6SGeorge Liu 
4600ef5dc6SGeorge Liu         powerSupplyList.emplace_back(std::move(item));
47788fe6cfSLakshmi Yadlapati     }
4800ef5dc6SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size();
49a7210020SGeorge Liu }
50a7210020SGeorge Liu 
513e42a329SLakshmi Yadlapati inline void doPowerSupplyCollection(
523e42a329SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
533e42a329SLakshmi Yadlapati     const std::string& chassisId, const boost::system::error_code& ec,
543e42a329SLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths)
55a7210020SGeorge Liu {
563e42a329SLakshmi Yadlapati     if (ec)
57a7210020SGeorge Liu     {
583e42a329SLakshmi Yadlapati         if (ec.value() != EBADR)
593e42a329SLakshmi Yadlapati         {
603e42a329SLakshmi Yadlapati             BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
613e42a329SLakshmi Yadlapati             messages::internalError(asyncResp->res);
623e42a329SLakshmi Yadlapati         }
63a7210020SGeorge Liu         return;
64a7210020SGeorge Liu     }
65a7210020SGeorge Liu     asyncResp->res.addHeader(
66a7210020SGeorge Liu         boost::beast::http::field::link,
67a7210020SGeorge Liu         "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
68a7210020SGeorge Liu     asyncResp->res.jsonValue["@odata.type"] =
69a7210020SGeorge Liu         "#PowerSupplyCollection.PowerSupplyCollection";
70a7210020SGeorge Liu     asyncResp->res.jsonValue["Name"] = "Power Supply Collection";
71ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
72ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId);
73a7210020SGeorge Liu     asyncResp->res.jsonValue["Description"] =
74a7210020SGeorge Liu         "The collection of PowerSupply resource instances.";
757a2bb2c9SGeorge Liu     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
767a2bb2c9SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = 0;
77a7210020SGeorge Liu 
78788fe6cfSLakshmi Yadlapati     updatePowerSupplyList(asyncResp, chassisId, subtreePaths);
79a7210020SGeorge Liu }
80a7210020SGeorge Liu 
81a7210020SGeorge Liu inline void handlePowerSupplyCollectionHead(
82a7210020SGeorge Liu     App& app, const crow::Request& req,
83a7210020SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
84a7210020SGeorge Liu     const std::string& chassisId)
85a7210020SGeorge Liu {
86a7210020SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
87a7210020SGeorge Liu     {
88a7210020SGeorge Liu         return;
89a7210020SGeorge Liu     }
90a7210020SGeorge Liu 
91a7210020SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
92a7210020SGeorge Liu         asyncResp, chassisId,
93a7210020SGeorge Liu         [asyncResp,
94a7210020SGeorge Liu          chassisId](const std::optional<std::string>& validChassisPath) {
95a7210020SGeorge Liu             if (!validChassisPath)
96a7210020SGeorge Liu             {
97bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res, "Chassis",
98bd79bce8SPatrick Williams                                            chassisId);
99a7210020SGeorge Liu                 return;
100a7210020SGeorge Liu             }
101a7210020SGeorge Liu             asyncResp->res.addHeader(
102a7210020SGeorge Liu                 boost::beast::http::field::link,
103a7210020SGeorge Liu                 "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
104a7210020SGeorge Liu         });
105a7210020SGeorge Liu }
106a7210020SGeorge Liu 
107a7210020SGeorge Liu inline void handlePowerSupplyCollectionGet(
108a7210020SGeorge Liu     App& app, const crow::Request& req,
109a7210020SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
110a7210020SGeorge Liu     const std::string& chassisId)
111a7210020SGeorge Liu {
112a7210020SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
113a7210020SGeorge Liu     {
114a7210020SGeorge Liu         return;
115a7210020SGeorge Liu     }
116a7210020SGeorge Liu 
1173e42a329SLakshmi Yadlapati     constexpr std::array<std::string_view, 2> chasisInterfaces = {
1183e42a329SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.Board",
1193e42a329SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.Chassis"};
1203e42a329SLakshmi Yadlapati     const std::string reqpath = "/xyz/openbmc_project/inventory";
1213e42a329SLakshmi Yadlapati 
1223e42a329SLakshmi Yadlapati     dbus::utility::getAssociatedSubTreePathsById(
1233e42a329SLakshmi Yadlapati         chassisId, reqpath, chasisInterfaces, "powered_by",
1243e42a329SLakshmi Yadlapati         powerSupplyInterface,
1253e42a329SLakshmi Yadlapati         [asyncResp, chassisId](
1263e42a329SLakshmi Yadlapati             const boost::system::error_code& ec,
1273e42a329SLakshmi Yadlapati             const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
1283e42a329SLakshmi Yadlapati             doPowerSupplyCollection(asyncResp, chassisId, ec, subtreePaths);
1293e42a329SLakshmi Yadlapati         });
130a7210020SGeorge Liu }
131a7210020SGeorge Liu 
132a7210020SGeorge Liu inline void requestRoutesPowerSupplyCollection(App& app)
133a7210020SGeorge Liu {
134a7210020SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
135a7210020SGeorge Liu         .privileges(redfish::privileges::headPowerSupplyCollection)
136a7210020SGeorge Liu         .methods(boost::beast::http::verb::head)(
137a7210020SGeorge Liu             std::bind_front(handlePowerSupplyCollectionHead, std::ref(app)));
138a7210020SGeorge Liu 
139a7210020SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
140a7210020SGeorge Liu         .privileges(redfish::privileges::getPowerSupplyCollection)
141a7210020SGeorge Liu         .methods(boost::beast::http::verb::get)(
142a7210020SGeorge Liu             std::bind_front(handlePowerSupplyCollectionGet, std::ref(app)));
143a7210020SGeorge Liu }
144a7210020SGeorge Liu 
1453e42a329SLakshmi Yadlapati inline void afterGetValidPowerSupplyPath(
14634dfcb94SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1473e42a329SLakshmi Yadlapati     const std::string& powerSupplyId, const boost::system::error_code& ec,
1483e42a329SLakshmi Yadlapati     const dbus::utility::MapperGetSubTreeResponse& subtree,
1493e42a329SLakshmi Yadlapati     const std::function<void(const std::string& powerSupplyPath,
1503e42a329SLakshmi Yadlapati                              const std::string& service)>& callback)
15100ef5dc6SGeorge Liu {
15200ef5dc6SGeorge Liu     if (ec)
15300ef5dc6SGeorge Liu     {
15400ef5dc6SGeorge Liu         if (ec.value() != EBADR)
15500ef5dc6SGeorge Liu         {
1563e42a329SLakshmi Yadlapati             BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
15700ef5dc6SGeorge Liu             messages::internalError(asyncResp->res);
1583e42a329SLakshmi Yadlapati         }
15900ef5dc6SGeorge Liu         return;
16000ef5dc6SGeorge Liu     }
1613e42a329SLakshmi Yadlapati     for (const auto& [objectPath, service] : subtree)
16200ef5dc6SGeorge Liu     {
1633e42a329SLakshmi Yadlapati         sdbusplus::message::object_path path(objectPath);
1643e42a329SLakshmi Yadlapati         if (path == powerSupplyId)
16500ef5dc6SGeorge Liu         {
1663e42a329SLakshmi Yadlapati             callback(path, service.begin()->first);
16700ef5dc6SGeorge Liu             return;
16800ef5dc6SGeorge Liu         }
16900ef5dc6SGeorge Liu     }
17000ef5dc6SGeorge Liu 
17162598e31SEd Tanous     BMCWEB_LOG_WARNING("Power supply not found: {}", powerSupplyId);
1723e42a329SLakshmi Yadlapati     messages::resourceNotFound(asyncResp->res, "PowerSupplies", powerSupplyId);
17300ef5dc6SGeorge Liu }
1743e42a329SLakshmi Yadlapati 
1753e42a329SLakshmi Yadlapati inline void getValidPowerSupplyPath(
1763e42a329SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1773e42a329SLakshmi Yadlapati     const std::string& chassisId, const std::string& powerSupplyId,
1783e42a329SLakshmi Yadlapati     std::function<void(const std::string& powerSupplyPath,
1793e42a329SLakshmi Yadlapati                        const std::string& service)>&& callback)
1803e42a329SLakshmi Yadlapati {
1813e42a329SLakshmi Yadlapati     constexpr std::array<std::string_view, 2> chasisInterfaces = {
1823e42a329SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.Board",
1833e42a329SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.Chassis"};
1843e42a329SLakshmi Yadlapati     const std::string reqpath = "/xyz/openbmc_project/inventory";
1853e42a329SLakshmi Yadlapati 
1863e42a329SLakshmi Yadlapati     dbus::utility::getAssociatedSubTreeById(
1873e42a329SLakshmi Yadlapati         chassisId, reqpath, chasisInterfaces, "powered_by",
1883e42a329SLakshmi Yadlapati         powerSupplyInterface,
1893e42a329SLakshmi Yadlapati         [asyncResp, chassisId, powerSupplyId, callback{std::move(callback)}](
1903e42a329SLakshmi Yadlapati             const boost::system::error_code& ec,
1913e42a329SLakshmi Yadlapati             const dbus::utility::MapperGetSubTreeResponse& subtree) {
1923e42a329SLakshmi Yadlapati             afterGetValidPowerSupplyPath(asyncResp, powerSupplyId, ec, subtree,
1933e42a329SLakshmi Yadlapati                                          callback);
19400ef5dc6SGeorge Liu         });
19500ef5dc6SGeorge Liu }
19600ef5dc6SGeorge Liu 
19700ef5dc6SGeorge Liu inline void
19834dfcb94SGeorge Liu     getPowerSupplyState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
19934dfcb94SGeorge Liu                         const std::string& service, const std::string& path)
20034dfcb94SGeorge Liu {
20134dfcb94SGeorge Liu     sdbusplus::asio::getProperty<bool>(
20234dfcb94SGeorge Liu         *crow::connections::systemBus, service, path,
20334dfcb94SGeorge Liu         "xyz.openbmc_project.Inventory.Item", "Present",
20434dfcb94SGeorge Liu         [asyncResp](const boost::system::error_code& ec, const bool value) {
20534dfcb94SGeorge Liu             if (ec)
20634dfcb94SGeorge Liu             {
20734dfcb94SGeorge Liu                 if (ec.value() != EBADR)
20834dfcb94SGeorge Liu                 {
20962598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for State {}",
21062598e31SEd Tanous                                      ec.value());
21134dfcb94SGeorge Liu                     messages::internalError(asyncResp->res);
21234dfcb94SGeorge Liu                 }
21334dfcb94SGeorge Liu                 return;
21434dfcb94SGeorge Liu             }
21534dfcb94SGeorge Liu 
21634dfcb94SGeorge Liu             if (!value)
21734dfcb94SGeorge Liu             {
218539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
219539d8c6bSEd Tanous                     resource::State::Absent;
22034dfcb94SGeorge Liu             }
22134dfcb94SGeorge Liu         });
22234dfcb94SGeorge Liu }
22334dfcb94SGeorge Liu 
22434dfcb94SGeorge Liu inline void
22534dfcb94SGeorge Liu     getPowerSupplyHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
22634dfcb94SGeorge Liu                          const std::string& service, const std::string& path)
22734dfcb94SGeorge Liu {
22834dfcb94SGeorge Liu     sdbusplus::asio::getProperty<bool>(
22934dfcb94SGeorge Liu         *crow::connections::systemBus, service, path,
23034dfcb94SGeorge Liu         "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
23134dfcb94SGeorge Liu         [asyncResp](const boost::system::error_code& ec, const bool value) {
23234dfcb94SGeorge Liu             if (ec)
23334dfcb94SGeorge Liu             {
23434dfcb94SGeorge Liu                 if (ec.value() != EBADR)
23534dfcb94SGeorge Liu                 {
23662598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Health {}",
23762598e31SEd Tanous                                      ec.value());
23834dfcb94SGeorge Liu                     messages::internalError(asyncResp->res);
23934dfcb94SGeorge Liu                 }
24034dfcb94SGeorge Liu                 return;
24134dfcb94SGeorge Liu             }
24234dfcb94SGeorge Liu 
24334dfcb94SGeorge Liu             if (!value)
24434dfcb94SGeorge Liu             {
245539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["Health"] =
246539d8c6bSEd Tanous                     resource::Health::Critical;
24734dfcb94SGeorge Liu             }
24834dfcb94SGeorge Liu         });
24934dfcb94SGeorge Liu }
25034dfcb94SGeorge Liu 
25134dfcb94SGeorge Liu inline void
2522b45fb3bSGeorge Liu     getPowerSupplyAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2532b45fb3bSGeorge Liu                         const std::string& service, const std::string& path)
2542b45fb3bSGeorge Liu {
2552b45fb3bSGeorge Liu     sdbusplus::asio::getAllProperties(
2562b45fb3bSGeorge Liu         *crow::connections::systemBus, service, path,
2572b45fb3bSGeorge Liu         "xyz.openbmc_project.Inventory.Decorator.Asset",
2582b45fb3bSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
2592b45fb3bSGeorge Liu                     const dbus::utility::DBusPropertiesMap& propertiesList) {
2602b45fb3bSGeorge Liu             if (ec)
2612b45fb3bSGeorge Liu             {
2622b45fb3bSGeorge Liu                 if (ec.value() != EBADR)
2632b45fb3bSGeorge Liu                 {
26462598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Asset {}",
26562598e31SEd Tanous                                      ec.value());
2662b45fb3bSGeorge Liu                     messages::internalError(asyncResp->res);
2672b45fb3bSGeorge Liu                 }
2682b45fb3bSGeorge Liu                 return;
2692b45fb3bSGeorge Liu             }
2702b45fb3bSGeorge Liu 
2712b45fb3bSGeorge Liu             const std::string* partNumber = nullptr;
2722b45fb3bSGeorge Liu             const std::string* serialNumber = nullptr;
2732b45fb3bSGeorge Liu             const std::string* manufacturer = nullptr;
2742b45fb3bSGeorge Liu             const std::string* model = nullptr;
2752b45fb3bSGeorge Liu             const std::string* sparePartNumber = nullptr;
276*b5190062SHieu Huynh             const std::string* buildDate = nullptr;
2772b45fb3bSGeorge Liu 
2782b45fb3bSGeorge Liu             const bool success = sdbusplus::unpackPropertiesNoThrow(
2792b45fb3bSGeorge Liu                 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
2802b45fb3bSGeorge Liu                 partNumber, "SerialNumber", serialNumber, "Manufacturer",
281bd79bce8SPatrick Williams                 manufacturer, "Model", model, "SparePartNumber",
282*b5190062SHieu Huynh                 sparePartNumber, "BuildDate", buildDate);
2832b45fb3bSGeorge Liu 
2842b45fb3bSGeorge Liu             if (!success)
2852b45fb3bSGeorge Liu             {
2862b45fb3bSGeorge Liu                 messages::internalError(asyncResp->res);
2872b45fb3bSGeorge Liu                 return;
2882b45fb3bSGeorge Liu             }
2892b45fb3bSGeorge Liu 
2902b45fb3bSGeorge Liu             if (partNumber != nullptr)
2912b45fb3bSGeorge Liu             {
2922b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
2932b45fb3bSGeorge Liu             }
2942b45fb3bSGeorge Liu 
2952b45fb3bSGeorge Liu             if (serialNumber != nullptr)
2962b45fb3bSGeorge Liu             {
2972b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
2982b45fb3bSGeorge Liu             }
2992b45fb3bSGeorge Liu 
3002b45fb3bSGeorge Liu             if (manufacturer != nullptr)
3012b45fb3bSGeorge Liu             {
3022b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
3032b45fb3bSGeorge Liu             }
3042b45fb3bSGeorge Liu 
3052b45fb3bSGeorge Liu             if (model != nullptr)
3062b45fb3bSGeorge Liu             {
3072b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["Model"] = *model;
3082b45fb3bSGeorge Liu             }
3092b45fb3bSGeorge Liu 
3102b45fb3bSGeorge Liu             // SparePartNumber is optional on D-Bus so skip if it is empty
3112b45fb3bSGeorge Liu             if (sparePartNumber != nullptr && !sparePartNumber->empty())
3122b45fb3bSGeorge Liu             {
3132b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
3142b45fb3bSGeorge Liu             }
315*b5190062SHieu Huynh 
316*b5190062SHieu Huynh             if (buildDate != nullptr)
317*b5190062SHieu Huynh             {
318*b5190062SHieu Huynh                 time_utils::productionDateReport(asyncResp->res, *buildDate);
319*b5190062SHieu Huynh             }
3202b45fb3bSGeorge Liu         });
3212b45fb3bSGeorge Liu }
3222b45fb3bSGeorge Liu 
323a0dba87bSGeorge Liu inline void getPowerSupplyFirmwareVersion(
324a0dba87bSGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
325a0dba87bSGeorge Liu     const std::string& service, const std::string& path)
326a0dba87bSGeorge Liu {
327a0dba87bSGeorge Liu     sdbusplus::asio::getProperty<std::string>(
328a0dba87bSGeorge Liu         *crow::connections::systemBus, service, path,
329a0dba87bSGeorge Liu         "xyz.openbmc_project.Software.Version", "Version",
330a0dba87bSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
331a0dba87bSGeorge Liu                     const std::string& value) {
332a0dba87bSGeorge Liu             if (ec)
333a0dba87bSGeorge Liu             {
334a0dba87bSGeorge Liu                 if (ec.value() != EBADR)
335a0dba87bSGeorge Liu                 {
336bd79bce8SPatrick Williams                     BMCWEB_LOG_ERROR(
337bd79bce8SPatrick Williams                         "DBUS response error for FirmwareVersion {}",
33862598e31SEd Tanous                         ec.value());
339a0dba87bSGeorge Liu                     messages::internalError(asyncResp->res);
340a0dba87bSGeorge Liu                 }
341a0dba87bSGeorge Liu                 return;
342a0dba87bSGeorge Liu             }
343a0dba87bSGeorge Liu             asyncResp->res.jsonValue["FirmwareVersion"] = value;
344a0dba87bSGeorge Liu         });
345a0dba87bSGeorge Liu }
346a0dba87bSGeorge Liu 
3472b45fb3bSGeorge Liu inline void
34844845e5fSGeorge Liu     getPowerSupplyLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
34944845e5fSGeorge Liu                            const std::string& service, const std::string& path)
35044845e5fSGeorge Liu {
35144845e5fSGeorge Liu     sdbusplus::asio::getProperty<std::string>(
35244845e5fSGeorge Liu         *crow::connections::systemBus, service, path,
35344845e5fSGeorge Liu         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
35444845e5fSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
35544845e5fSGeorge Liu                     const std::string& value) {
35644845e5fSGeorge Liu             if (ec)
35744845e5fSGeorge Liu             {
35844845e5fSGeorge Liu                 if (ec.value() != EBADR)
35944845e5fSGeorge Liu                 {
36062598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Location {}",
36162598e31SEd Tanous                                      ec.value());
36244845e5fSGeorge Liu                     messages::internalError(asyncResp->res);
36344845e5fSGeorge Liu                 }
36444845e5fSGeorge Liu                 return;
36544845e5fSGeorge Liu             }
366bd79bce8SPatrick Williams             asyncResp->res
367bd79bce8SPatrick Williams                 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = value;
36844845e5fSGeorge Liu         });
36944845e5fSGeorge Liu }
37044845e5fSGeorge Liu 
371ddceee07SGeorge Liu inline void handleGetEfficiencyResponse(
372ddceee07SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
373ddceee07SGeorge Liu     const boost::system::error_code& ec, uint32_t value)
374ddceee07SGeorge Liu {
375ddceee07SGeorge Liu     if (ec)
376ddceee07SGeorge Liu     {
377ddceee07SGeorge Liu         if (ec.value() != EBADR)
378ddceee07SGeorge Liu         {
37962598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for DeratingFactor {}",
38062598e31SEd Tanous                              ec.value());
381ddceee07SGeorge Liu             messages::internalError(asyncResp->res);
382ddceee07SGeorge Liu         }
383ddceee07SGeorge Liu         return;
384ddceee07SGeorge Liu     }
385ddceee07SGeorge Liu     // The PDI default value is 0, if it hasn't been set leave off
386ddceee07SGeorge Liu     if (value == 0)
387ddceee07SGeorge Liu     {
388ddceee07SGeorge Liu         return;
389ddceee07SGeorge Liu     }
390ddceee07SGeorge Liu 
391ddceee07SGeorge Liu     nlohmann::json::array_t efficiencyRatings;
392ddceee07SGeorge Liu     nlohmann::json::object_t efficiencyPercent;
393ddceee07SGeorge Liu     efficiencyPercent["EfficiencyPercent"] = value;
394ddceee07SGeorge Liu     efficiencyRatings.emplace_back(std::move(efficiencyPercent));
395ddceee07SGeorge Liu     asyncResp->res.jsonValue["EfficiencyRatings"] =
396ddceee07SGeorge Liu         std::move(efficiencyRatings);
397ddceee07SGeorge Liu }
398ddceee07SGeorge Liu 
399ddceee07SGeorge Liu inline void handlePowerSupplyAttributesSubTreeResponse(
400ddceee07SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
401ddceee07SGeorge Liu     const boost::system::error_code& ec,
402ddceee07SGeorge Liu     const dbus::utility::MapperGetSubTreeResponse& subtree)
403ddceee07SGeorge Liu {
404ddceee07SGeorge Liu     if (ec)
405ddceee07SGeorge Liu     {
406ddceee07SGeorge Liu         if (ec.value() != EBADR)
407ddceee07SGeorge Liu         {
40862598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for EfficiencyPercent {}",
40962598e31SEd Tanous                              ec.value());
410ddceee07SGeorge Liu             messages::internalError(asyncResp->res);
411ddceee07SGeorge Liu         }
412ddceee07SGeorge Liu         return;
413ddceee07SGeorge Liu     }
414ddceee07SGeorge Liu 
415ddceee07SGeorge Liu     if (subtree.empty())
416ddceee07SGeorge Liu     {
41762598e31SEd Tanous         BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
418ddceee07SGeorge Liu         return;
419ddceee07SGeorge Liu     }
420ddceee07SGeorge Liu 
421ddceee07SGeorge Liu     if (subtree.size() != 1)
422ddceee07SGeorge Liu     {
42362598e31SEd Tanous         BMCWEB_LOG_ERROR(
42462598e31SEd Tanous             "Unexpected number of paths returned by getSubTree: {}",
42562598e31SEd Tanous             subtree.size());
426ddceee07SGeorge Liu         messages::internalError(asyncResp->res);
427ddceee07SGeorge Liu         return;
428ddceee07SGeorge Liu     }
429ddceee07SGeorge Liu 
430ddceee07SGeorge Liu     const auto& [path, serviceMap] = *subtree.begin();
431ddceee07SGeorge Liu     const auto& [service, interfaces] = *serviceMap.begin();
432ddceee07SGeorge Liu     sdbusplus::asio::getProperty<uint32_t>(
433ddceee07SGeorge Liu         *crow::connections::systemBus, service, path,
434ddceee07SGeorge Liu         "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
435ddceee07SGeorge Liu         [asyncResp](const boost::system::error_code& ec1, uint32_t value) {
436ddceee07SGeorge Liu             handleGetEfficiencyResponse(asyncResp, ec1, value);
437ddceee07SGeorge Liu         });
438ddceee07SGeorge Liu }
439ddceee07SGeorge Liu 
440ddceee07SGeorge Liu inline void
441ddceee07SGeorge Liu     getEfficiencyPercent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
442ddceee07SGeorge Liu {
443ddceee07SGeorge Liu     constexpr std::array<std::string_view, 1> efficiencyIntf = {
444ddceee07SGeorge Liu         "xyz.openbmc_project.Control.PowerSupplyAttributes"};
445ddceee07SGeorge Liu 
446ddceee07SGeorge Liu     dbus::utility::getSubTree(
447ddceee07SGeorge Liu         "/xyz/openbmc_project", 0, efficiencyIntf,
448ddceee07SGeorge Liu         [asyncResp](const boost::system::error_code& ec,
449ddceee07SGeorge Liu                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
450ddceee07SGeorge Liu             handlePowerSupplyAttributesSubTreeResponse(asyncResp, ec, subtree);
451ddceee07SGeorge Liu         });
452ddceee07SGeorge Liu }
453ddceee07SGeorge Liu 
454bd79bce8SPatrick Williams inline void doPowerSupplyGet(
455bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
456bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& powerSupplyId,
4573e42a329SLakshmi Yadlapati     const std::string& powerSupplyPath, const std::string& service)
45800ef5dc6SGeorge Liu {
45900ef5dc6SGeorge Liu     asyncResp->res.addHeader(
46000ef5dc6SGeorge Liu         boost::beast::http::field::link,
46100ef5dc6SGeorge Liu         "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
4623e42a329SLakshmi Yadlapati     asyncResp->res.jsonValue["@odata.type"] = "#PowerSupply.v1_5_0.PowerSupply";
46300ef5dc6SGeorge Liu     asyncResp->res.jsonValue["Name"] = "Power Supply";
46400ef5dc6SGeorge Liu     asyncResp->res.jsonValue["Id"] = powerSupplyId;
46500ef5dc6SGeorge Liu     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
4663e42a329SLakshmi Yadlapati         "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
4673e42a329SLakshmi Yadlapati         powerSupplyId);
46834dfcb94SGeorge Liu 
4693e42a329SLakshmi Yadlapati     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
470539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
47134dfcb94SGeorge Liu 
4723e42a329SLakshmi Yadlapati     getPowerSupplyState(asyncResp, service, powerSupplyPath);
4733e42a329SLakshmi Yadlapati     getPowerSupplyHealth(asyncResp, service, powerSupplyPath);
4743e42a329SLakshmi Yadlapati     getPowerSupplyAsset(asyncResp, service, powerSupplyPath);
4753e42a329SLakshmi Yadlapati     getPowerSupplyFirmwareVersion(asyncResp, service, powerSupplyPath);
4763e42a329SLakshmi Yadlapati     getPowerSupplyLocation(asyncResp, service, powerSupplyPath);
477ddceee07SGeorge Liu     getEfficiencyPercent(asyncResp);
47800ef5dc6SGeorge Liu }
47900ef5dc6SGeorge Liu 
480bd79bce8SPatrick Williams inline void handlePowerSupplyHead(
481bd79bce8SPatrick Williams     App& app, const crow::Request& req,
48200ef5dc6SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
483bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& powerSupplyId)
48400ef5dc6SGeorge Liu {
48500ef5dc6SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
48600ef5dc6SGeorge Liu     {
48700ef5dc6SGeorge Liu         return;
48800ef5dc6SGeorge Liu     }
48900ef5dc6SGeorge Liu 
49000ef5dc6SGeorge Liu     // Get the correct Path and Service that match the input parameters
491bd79bce8SPatrick Williams     getValidPowerSupplyPath(
4923e42a329SLakshmi Yadlapati         asyncResp, chassisId, powerSupplyId,
4933e42a329SLakshmi Yadlapati         [asyncResp](const std::string&, const std::string&) {
49400ef5dc6SGeorge Liu             asyncResp->res.addHeader(
49500ef5dc6SGeorge Liu                 boost::beast::http::field::link,
49600ef5dc6SGeorge Liu                 "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
49700ef5dc6SGeorge Liu         });
49800ef5dc6SGeorge Liu }
49900ef5dc6SGeorge Liu 
500bd79bce8SPatrick Williams inline void handlePowerSupplyGet(
501bd79bce8SPatrick Williams     App& app, const crow::Request& req,
50200ef5dc6SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
503bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& powerSupplyId)
50400ef5dc6SGeorge Liu {
50500ef5dc6SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
50600ef5dc6SGeorge Liu     {
50700ef5dc6SGeorge Liu         return;
50800ef5dc6SGeorge Liu     }
5093e42a329SLakshmi Yadlapati     getValidPowerSupplyPath(
5103e42a329SLakshmi Yadlapati         asyncResp, chassisId, powerSupplyId,
51100ef5dc6SGeorge Liu         std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId));
51200ef5dc6SGeorge Liu }
51300ef5dc6SGeorge Liu 
51400ef5dc6SGeorge Liu inline void requestRoutesPowerSupply(App& app)
51500ef5dc6SGeorge Liu {
51600ef5dc6SGeorge Liu     BMCWEB_ROUTE(
51700ef5dc6SGeorge Liu         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
51800ef5dc6SGeorge Liu         .privileges(redfish::privileges::headPowerSupply)
51900ef5dc6SGeorge Liu         .methods(boost::beast::http::verb::head)(
52000ef5dc6SGeorge Liu             std::bind_front(handlePowerSupplyHead, std::ref(app)));
52100ef5dc6SGeorge Liu 
52200ef5dc6SGeorge Liu     BMCWEB_ROUTE(
52300ef5dc6SGeorge Liu         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
52400ef5dc6SGeorge Liu         .privileges(redfish::privileges::getPowerSupply)
52500ef5dc6SGeorge Liu         .methods(boost::beast::http::verb::get)(
52600ef5dc6SGeorge Liu             std::bind_front(handlePowerSupplyGet, std::ref(app)));
52700ef5dc6SGeorge Liu }
52800ef5dc6SGeorge Liu 
529a7210020SGeorge Liu } // namespace redfish
530