xref: /openbmc/bmcweb/features/redfish/lib/power_supply.hpp (revision f7e62c142ced153e9400b519bdd66062dd6bbf0e)
140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3a7210020SGeorge Liu #pragma once
4a7210020SGeorge Liu 
5a7210020SGeorge Liu #include "app.hpp"
6d7857201SEd Tanous #include "async_resp.hpp"
7a7210020SGeorge Liu #include "dbus_utility.hpp"
8d7857201SEd Tanous #include "error_messages.hpp"
9539d8c6bSEd Tanous #include "generated/enums/resource.hpp"
10d7857201SEd Tanous #include "http_request.hpp"
117066dc58SMyung Bae #include "led.hpp"
12d7857201SEd Tanous #include "logging.hpp"
13a7210020SGeorge Liu #include "query.hpp"
14a7210020SGeorge Liu #include "registries/privilege_registry.hpp"
15*f7e62c14SMyung Bae #include "utils/asset_utils.hpp"
16a7210020SGeorge Liu #include "utils/chassis_utils.hpp"
172b45fb3bSGeorge Liu #include "utils/dbus_utils.hpp"
187066dc58SMyung Bae #include "utils/json_utils.hpp"
19b5190062SHieu Huynh #include "utils/time_utils.hpp"
20a7210020SGeorge Liu 
21d7857201SEd Tanous #include <asm-generic/errno.h>
22d7857201SEd Tanous 
23d7857201SEd Tanous #include <boost/beast/http/field.hpp>
24d7857201SEd Tanous #include <boost/beast/http/verb.hpp>
2534dfcb94SGeorge Liu #include <boost/system/error_code.hpp>
26ef4c65b7SEd Tanous #include <boost/url/format.hpp>
27d7857201SEd Tanous #include <nlohmann/json.hpp>
28d7857201SEd Tanous #include <sdbusplus/unpack_properties.hpp>
29ef4c65b7SEd Tanous 
30d7857201SEd Tanous #include <array>
31d7857201SEd Tanous #include <cstdint>
32d7857201SEd Tanous #include <functional>
33a7210020SGeorge Liu #include <memory>
34a7210020SGeorge Liu #include <optional>
35a7210020SGeorge Liu #include <string>
36d7857201SEd Tanous #include <string_view>
37d7857201SEd Tanous #include <utility>
38a7210020SGeorge Liu 
39a7210020SGeorge Liu namespace redfish
40a7210020SGeorge Liu {
41a7210020SGeorge Liu 
42788fe6cfSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> powerSupplyInterface = {
43788fe6cfSLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PowerSupply"};
44788fe6cfSLakshmi Yadlapati 
45788fe6cfSLakshmi Yadlapati inline void updatePowerSupplyList(
46788fe6cfSLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4700ef5dc6SGeorge Liu     const std::string& chassisId,
48788fe6cfSLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& powerSupplyPaths)
49788fe6cfSLakshmi Yadlapati {
50788fe6cfSLakshmi Yadlapati     nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"];
51788fe6cfSLakshmi Yadlapati     for (const std::string& powerSupplyPath : powerSupplyPaths)
52a7210020SGeorge Liu     {
5300ef5dc6SGeorge Liu         std::string powerSupplyName =
5400ef5dc6SGeorge Liu             sdbusplus::message::object_path(powerSupplyPath).filename();
5500ef5dc6SGeorge Liu         if (powerSupplyName.empty())
5600ef5dc6SGeorge Liu         {
57788fe6cfSLakshmi Yadlapati             continue;
5800ef5dc6SGeorge Liu         }
5900ef5dc6SGeorge Liu 
6000ef5dc6SGeorge Liu         nlohmann::json item = nlohmann::json::object();
6100ef5dc6SGeorge Liu         item["@odata.id"] = boost::urls::format(
6200ef5dc6SGeorge Liu             "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
6300ef5dc6SGeorge Liu             powerSupplyName);
6400ef5dc6SGeorge Liu 
6500ef5dc6SGeorge Liu         powerSupplyList.emplace_back(std::move(item));
66788fe6cfSLakshmi Yadlapati     }
6700ef5dc6SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size();
68a7210020SGeorge Liu }
69a7210020SGeorge Liu 
703e42a329SLakshmi Yadlapati inline void doPowerSupplyCollection(
713e42a329SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
723e42a329SLakshmi Yadlapati     const std::string& chassisId, const boost::system::error_code& ec,
733e42a329SLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths)
74a7210020SGeorge Liu {
753e42a329SLakshmi Yadlapati     if (ec)
76a7210020SGeorge Liu     {
77193582b6SMyung Bae         if (ec.value() == boost::system::errc::io_error)
78193582b6SMyung Bae         {
79193582b6SMyung Bae             BMCWEB_LOG_WARNING("Chassis not found");
80193582b6SMyung Bae             messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
81193582b6SMyung Bae             return;
82193582b6SMyung Bae         }
833e42a329SLakshmi Yadlapati         if (ec.value() != EBADR)
843e42a329SLakshmi Yadlapati         {
853e42a329SLakshmi Yadlapati             BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
863e42a329SLakshmi Yadlapati             messages::internalError(asyncResp->res);
873e42a329SLakshmi Yadlapati         }
88a7210020SGeorge Liu         return;
89a7210020SGeorge Liu     }
90a7210020SGeorge Liu     asyncResp->res.addHeader(
91a7210020SGeorge Liu         boost::beast::http::field::link,
92a7210020SGeorge Liu         "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
93a7210020SGeorge Liu     asyncResp->res.jsonValue["@odata.type"] =
94a7210020SGeorge Liu         "#PowerSupplyCollection.PowerSupplyCollection";
95a7210020SGeorge Liu     asyncResp->res.jsonValue["Name"] = "Power Supply Collection";
96ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
97ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId);
98a7210020SGeorge Liu     asyncResp->res.jsonValue["Description"] =
99a7210020SGeorge Liu         "The collection of PowerSupply resource instances.";
1007a2bb2c9SGeorge Liu     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
1017a2bb2c9SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = 0;
102a7210020SGeorge Liu 
103788fe6cfSLakshmi Yadlapati     updatePowerSupplyList(asyncResp, chassisId, subtreePaths);
104a7210020SGeorge Liu }
105a7210020SGeorge Liu 
106a7210020SGeorge Liu inline void handlePowerSupplyCollectionHead(
107a7210020SGeorge Liu     App& app, const crow::Request& req,
108a7210020SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
109a7210020SGeorge Liu     const std::string& chassisId)
110a7210020SGeorge Liu {
111a7210020SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
112a7210020SGeorge Liu     {
113a7210020SGeorge Liu         return;
114a7210020SGeorge Liu     }
115a7210020SGeorge Liu 
116a7210020SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
117a7210020SGeorge Liu         asyncResp, chassisId,
118a7210020SGeorge Liu         [asyncResp,
119a7210020SGeorge Liu          chassisId](const std::optional<std::string>& validChassisPath) {
120a7210020SGeorge Liu             if (!validChassisPath)
121a7210020SGeorge Liu             {
122193582b6SMyung Bae                 BMCWEB_LOG_WARNING("Chassis not found");
123bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res, "Chassis",
124bd79bce8SPatrick Williams                                            chassisId);
125a7210020SGeorge Liu                 return;
126a7210020SGeorge Liu             }
127a7210020SGeorge Liu             asyncResp->res.addHeader(
128a7210020SGeorge Liu                 boost::beast::http::field::link,
129a7210020SGeorge Liu                 "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
130a7210020SGeorge Liu         });
131a7210020SGeorge Liu }
132a7210020SGeorge Liu 
133a7210020SGeorge Liu inline void handlePowerSupplyCollectionGet(
134a7210020SGeorge Liu     App& app, const crow::Request& req,
135a7210020SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
136a7210020SGeorge Liu     const std::string& chassisId)
137a7210020SGeorge Liu {
138a7210020SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
139a7210020SGeorge Liu     {
140a7210020SGeorge Liu         return;
141a7210020SGeorge Liu     }
142a7210020SGeorge Liu 
1433e42a329SLakshmi Yadlapati     const std::string reqpath = "/xyz/openbmc_project/inventory";
1443e42a329SLakshmi Yadlapati 
1453e42a329SLakshmi Yadlapati     dbus::utility::getAssociatedSubTreePathsById(
1463f95a277SMyung Bae         chassisId, reqpath, chassisInterfaces, "powered_by",
1473e42a329SLakshmi Yadlapati         powerSupplyInterface,
1483e42a329SLakshmi Yadlapati         [asyncResp, chassisId](
1493e42a329SLakshmi Yadlapati             const boost::system::error_code& ec,
1503e42a329SLakshmi Yadlapati             const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
1513e42a329SLakshmi Yadlapati             doPowerSupplyCollection(asyncResp, chassisId, ec, subtreePaths);
1523e42a329SLakshmi Yadlapati         });
153a7210020SGeorge Liu }
154a7210020SGeorge Liu 
155a7210020SGeorge Liu inline void requestRoutesPowerSupplyCollection(App& app)
156a7210020SGeorge Liu {
157a7210020SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
158a7210020SGeorge Liu         .privileges(redfish::privileges::headPowerSupplyCollection)
159a7210020SGeorge Liu         .methods(boost::beast::http::verb::head)(
160a7210020SGeorge Liu             std::bind_front(handlePowerSupplyCollectionHead, std::ref(app)));
161a7210020SGeorge Liu 
162a7210020SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
163a7210020SGeorge Liu         .privileges(redfish::privileges::getPowerSupplyCollection)
164a7210020SGeorge Liu         .methods(boost::beast::http::verb::get)(
165a7210020SGeorge Liu             std::bind_front(handlePowerSupplyCollectionGet, std::ref(app)));
166a7210020SGeorge Liu }
167a7210020SGeorge Liu 
1683e42a329SLakshmi Yadlapati inline void afterGetValidPowerSupplyPath(
16934dfcb94SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1703e42a329SLakshmi Yadlapati     const std::string& powerSupplyId, const boost::system::error_code& ec,
1713e42a329SLakshmi Yadlapati     const dbus::utility::MapperGetSubTreeResponse& subtree,
1723e42a329SLakshmi Yadlapati     const std::function<void(const std::string& powerSupplyPath,
1733e42a329SLakshmi Yadlapati                              const std::string& service)>& callback)
17400ef5dc6SGeorge Liu {
17500ef5dc6SGeorge Liu     if (ec)
17600ef5dc6SGeorge Liu     {
177193582b6SMyung Bae         if (ec.value() == boost::system::errc::io_error)
178193582b6SMyung Bae         {
179193582b6SMyung Bae             // Not found
180193582b6SMyung Bae             callback(std::string(), std::string());
181193582b6SMyung Bae             return;
182193582b6SMyung Bae         }
18300ef5dc6SGeorge Liu         if (ec.value() != EBADR)
18400ef5dc6SGeorge Liu         {
1853e42a329SLakshmi Yadlapati             BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
18600ef5dc6SGeorge Liu             messages::internalError(asyncResp->res);
187193582b6SMyung Bae             return;
1883e42a329SLakshmi Yadlapati         }
189193582b6SMyung Bae         callback(std::string(), std::string());
19000ef5dc6SGeorge Liu         return;
19100ef5dc6SGeorge Liu     }
1923e42a329SLakshmi Yadlapati     for (const auto& [objectPath, service] : subtree)
19300ef5dc6SGeorge Liu     {
1943e42a329SLakshmi Yadlapati         sdbusplus::message::object_path path(objectPath);
195d8e2b618SMyung Bae         if (path.filename() == powerSupplyId)
19600ef5dc6SGeorge Liu         {
1973e42a329SLakshmi Yadlapati             callback(path, service.begin()->first);
19800ef5dc6SGeorge Liu             return;
19900ef5dc6SGeorge Liu         }
20000ef5dc6SGeorge Liu     }
20100ef5dc6SGeorge Liu 
20262598e31SEd Tanous     BMCWEB_LOG_WARNING("Power supply not found: {}", powerSupplyId);
2033e42a329SLakshmi Yadlapati     messages::resourceNotFound(asyncResp->res, "PowerSupplies", powerSupplyId);
20400ef5dc6SGeorge Liu }
2053e42a329SLakshmi Yadlapati 
2063e42a329SLakshmi Yadlapati inline void getValidPowerSupplyPath(
2073e42a329SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2083e42a329SLakshmi Yadlapati     const std::string& chassisId, const std::string& powerSupplyId,
2093e42a329SLakshmi Yadlapati     std::function<void(const std::string& powerSupplyPath,
2103e42a329SLakshmi Yadlapati                        const std::string& service)>&& callback)
2113e42a329SLakshmi Yadlapati {
2123e42a329SLakshmi Yadlapati     const std::string reqpath = "/xyz/openbmc_project/inventory";
2133e42a329SLakshmi Yadlapati 
2143e42a329SLakshmi Yadlapati     dbus::utility::getAssociatedSubTreeById(
2153f95a277SMyung Bae         chassisId, reqpath, chassisInterfaces, "powered_by",
2163e42a329SLakshmi Yadlapati         powerSupplyInterface,
2173e42a329SLakshmi Yadlapati         [asyncResp, chassisId, powerSupplyId, callback{std::move(callback)}](
2183e42a329SLakshmi Yadlapati             const boost::system::error_code& ec,
2193e42a329SLakshmi Yadlapati             const dbus::utility::MapperGetSubTreeResponse& subtree) {
2203e42a329SLakshmi Yadlapati             afterGetValidPowerSupplyPath(asyncResp, powerSupplyId, ec, subtree,
2213e42a329SLakshmi Yadlapati                                          callback);
22200ef5dc6SGeorge Liu         });
22300ef5dc6SGeorge Liu }
22400ef5dc6SGeorge Liu 
225504af5a0SPatrick Williams inline void getPowerSupplyState(
226504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
22734dfcb94SGeorge Liu     const std::string& service, const std::string& path)
22834dfcb94SGeorge Liu {
229deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
230deae6a78SEd Tanous         service, path, "xyz.openbmc_project.Inventory.Item", "Present",
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 State {}",
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"]["State"] =
246539d8c6bSEd Tanous                     resource::State::Absent;
24734dfcb94SGeorge Liu             }
24834dfcb94SGeorge Liu         });
24934dfcb94SGeorge Liu }
25034dfcb94SGeorge Liu 
251504af5a0SPatrick Williams inline void getPowerSupplyHealth(
252504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
25334dfcb94SGeorge Liu     const std::string& service, const std::string& path)
25434dfcb94SGeorge Liu {
255deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
256deae6a78SEd Tanous         service, path, "xyz.openbmc_project.State.Decorator.OperationalStatus",
257deae6a78SEd Tanous         "Functional",
25834dfcb94SGeorge Liu         [asyncResp](const boost::system::error_code& ec, const bool value) {
25934dfcb94SGeorge Liu             if (ec)
26034dfcb94SGeorge Liu             {
26134dfcb94SGeorge Liu                 if (ec.value() != EBADR)
26234dfcb94SGeorge Liu                 {
26362598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Health {}",
26462598e31SEd Tanous                                      ec.value());
26534dfcb94SGeorge Liu                     messages::internalError(asyncResp->res);
26634dfcb94SGeorge Liu                 }
26734dfcb94SGeorge Liu                 return;
26834dfcb94SGeorge Liu             }
26934dfcb94SGeorge Liu 
27034dfcb94SGeorge Liu             if (!value)
27134dfcb94SGeorge Liu             {
272539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["Health"] =
273539d8c6bSEd Tanous                     resource::Health::Critical;
27434dfcb94SGeorge Liu             }
27534dfcb94SGeorge Liu         });
27634dfcb94SGeorge Liu }
27734dfcb94SGeorge Liu 
278504af5a0SPatrick Williams inline void getPowerSupplyAsset(
279504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2802b45fb3bSGeorge Liu     const std::string& service, const std::string& path)
2812b45fb3bSGeorge Liu {
282deae6a78SEd Tanous     dbus::utility::getAllProperties(
283deae6a78SEd Tanous         service, path, "xyz.openbmc_project.Inventory.Decorator.Asset",
2842b45fb3bSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
2852b45fb3bSGeorge Liu                     const dbus::utility::DBusPropertiesMap& propertiesList) {
2862b45fb3bSGeorge Liu             if (ec)
2872b45fb3bSGeorge Liu             {
2882b45fb3bSGeorge Liu                 if (ec.value() != EBADR)
2892b45fb3bSGeorge Liu                 {
29062598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Asset {}",
29162598e31SEd Tanous                                      ec.value());
2922b45fb3bSGeorge Liu                     messages::internalError(asyncResp->res);
2932b45fb3bSGeorge Liu                 }
2942b45fb3bSGeorge Liu                 return;
2952b45fb3bSGeorge Liu             }
2962b45fb3bSGeorge Liu 
297*f7e62c14SMyung Bae             asset_utils::extractAssetInfo(asyncResp, ""_json_pointer,
298*f7e62c14SMyung Bae                                           propertiesList, true);
299*f7e62c14SMyung Bae 
300b5190062SHieu Huynh             const std::string* buildDate = nullptr;
3012b45fb3bSGeorge Liu 
3022b45fb3bSGeorge Liu             const bool success = sdbusplus::unpackPropertiesNoThrow(
303*f7e62c14SMyung Bae                 dbus_utils::UnpackErrorPrinter(), propertiesList, "BuildDate",
304*f7e62c14SMyung Bae                 buildDate);
3052b45fb3bSGeorge Liu             if (!success)
3062b45fb3bSGeorge Liu             {
3072b45fb3bSGeorge Liu                 messages::internalError(asyncResp->res);
3082b45fb3bSGeorge Liu                 return;
3092b45fb3bSGeorge Liu             }
3102b45fb3bSGeorge Liu 
311b5190062SHieu Huynh             if (buildDate != nullptr)
312b5190062SHieu Huynh             {
313b5190062SHieu Huynh                 time_utils::productionDateReport(asyncResp->res, *buildDate);
314b5190062SHieu Huynh             }
3152b45fb3bSGeorge Liu         });
3162b45fb3bSGeorge Liu }
3172b45fb3bSGeorge Liu 
318a0dba87bSGeorge Liu inline void getPowerSupplyFirmwareVersion(
319a0dba87bSGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
320a0dba87bSGeorge Liu     const std::string& service, const std::string& path)
321a0dba87bSGeorge Liu {
322deae6a78SEd Tanous     dbus::utility::getProperty<std::string>(
323deae6a78SEd Tanous         service, path, "xyz.openbmc_project.Software.Version", "Version",
324a0dba87bSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
325a0dba87bSGeorge Liu                     const std::string& value) {
326a0dba87bSGeorge Liu             if (ec)
327a0dba87bSGeorge Liu             {
328a0dba87bSGeorge Liu                 if (ec.value() != EBADR)
329a0dba87bSGeorge Liu                 {
330bd79bce8SPatrick Williams                     BMCWEB_LOG_ERROR(
331bd79bce8SPatrick Williams                         "DBUS response error for FirmwareVersion {}",
33262598e31SEd Tanous                         ec.value());
333a0dba87bSGeorge Liu                     messages::internalError(asyncResp->res);
334a0dba87bSGeorge Liu                 }
335a0dba87bSGeorge Liu                 return;
336a0dba87bSGeorge Liu             }
337a0dba87bSGeorge Liu             asyncResp->res.jsonValue["FirmwareVersion"] = value;
338a0dba87bSGeorge Liu         });
339a0dba87bSGeorge Liu }
340a0dba87bSGeorge Liu 
341504af5a0SPatrick Williams inline void getPowerSupplyLocation(
342504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
34344845e5fSGeorge Liu     const std::string& service, const std::string& path)
34444845e5fSGeorge Liu {
345deae6a78SEd Tanous     dbus::utility::getProperty<std::string>(
346deae6a78SEd Tanous         service, path, "xyz.openbmc_project.Inventory.Decorator.LocationCode",
347deae6a78SEd Tanous         "LocationCode",
34844845e5fSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
34944845e5fSGeorge Liu                     const std::string& value) {
35044845e5fSGeorge Liu             if (ec)
35144845e5fSGeorge Liu             {
35244845e5fSGeorge Liu                 if (ec.value() != EBADR)
35344845e5fSGeorge Liu                 {
35462598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Location {}",
35562598e31SEd Tanous                                      ec.value());
35644845e5fSGeorge Liu                     messages::internalError(asyncResp->res);
35744845e5fSGeorge Liu                 }
35844845e5fSGeorge Liu                 return;
35944845e5fSGeorge Liu             }
360bd79bce8SPatrick Williams             asyncResp->res
361bd79bce8SPatrick Williams                 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = value;
36244845e5fSGeorge Liu         });
36344845e5fSGeorge Liu }
36444845e5fSGeorge Liu 
365ddceee07SGeorge Liu inline void handleGetEfficiencyResponse(
366ddceee07SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
367ddceee07SGeorge Liu     const boost::system::error_code& ec, uint32_t value)
368ddceee07SGeorge Liu {
369ddceee07SGeorge Liu     if (ec)
370ddceee07SGeorge Liu     {
371ddceee07SGeorge Liu         if (ec.value() != EBADR)
372ddceee07SGeorge Liu         {
37362598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for DeratingFactor {}",
37462598e31SEd Tanous                              ec.value());
375ddceee07SGeorge Liu             messages::internalError(asyncResp->res);
376ddceee07SGeorge Liu         }
377ddceee07SGeorge Liu         return;
378ddceee07SGeorge Liu     }
379ddceee07SGeorge Liu     // The PDI default value is 0, if it hasn't been set leave off
380ddceee07SGeorge Liu     if (value == 0)
381ddceee07SGeorge Liu     {
382ddceee07SGeorge Liu         return;
383ddceee07SGeorge Liu     }
384ddceee07SGeorge Liu 
385ddceee07SGeorge Liu     nlohmann::json::array_t efficiencyRatings;
386ddceee07SGeorge Liu     nlohmann::json::object_t efficiencyPercent;
387ddceee07SGeorge Liu     efficiencyPercent["EfficiencyPercent"] = value;
388ddceee07SGeorge Liu     efficiencyRatings.emplace_back(std::move(efficiencyPercent));
389ddceee07SGeorge Liu     asyncResp->res.jsonValue["EfficiencyRatings"] =
390ddceee07SGeorge Liu         std::move(efficiencyRatings);
391ddceee07SGeorge Liu }
392ddceee07SGeorge Liu 
393ddceee07SGeorge Liu inline void handlePowerSupplyAttributesSubTreeResponse(
394ddceee07SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
395ddceee07SGeorge Liu     const boost::system::error_code& ec,
396ddceee07SGeorge Liu     const dbus::utility::MapperGetSubTreeResponse& subtree)
397ddceee07SGeorge Liu {
398ddceee07SGeorge Liu     if (ec)
399ddceee07SGeorge Liu     {
400ddceee07SGeorge Liu         if (ec.value() != EBADR)
401ddceee07SGeorge Liu         {
40262598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for EfficiencyPercent {}",
40362598e31SEd Tanous                              ec.value());
404ddceee07SGeorge Liu             messages::internalError(asyncResp->res);
405ddceee07SGeorge Liu         }
406ddceee07SGeorge Liu         return;
407ddceee07SGeorge Liu     }
408ddceee07SGeorge Liu 
409ddceee07SGeorge Liu     if (subtree.empty())
410ddceee07SGeorge Liu     {
41162598e31SEd Tanous         BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
412ddceee07SGeorge Liu         return;
413ddceee07SGeorge Liu     }
414ddceee07SGeorge Liu 
415ddceee07SGeorge Liu     if (subtree.size() != 1)
416ddceee07SGeorge Liu     {
41762598e31SEd Tanous         BMCWEB_LOG_ERROR(
41862598e31SEd Tanous             "Unexpected number of paths returned by getSubTree: {}",
41962598e31SEd Tanous             subtree.size());
420ddceee07SGeorge Liu         messages::internalError(asyncResp->res);
421ddceee07SGeorge Liu         return;
422ddceee07SGeorge Liu     }
423ddceee07SGeorge Liu 
424ddceee07SGeorge Liu     const auto& [path, serviceMap] = *subtree.begin();
425ddceee07SGeorge Liu     const auto& [service, interfaces] = *serviceMap.begin();
426deae6a78SEd Tanous     dbus::utility::getProperty<uint32_t>(
427deae6a78SEd Tanous         service, path, "xyz.openbmc_project.Control.PowerSupplyAttributes",
428deae6a78SEd Tanous         "DeratingFactor",
429ddceee07SGeorge Liu         [asyncResp](const boost::system::error_code& ec1, uint32_t value) {
430ddceee07SGeorge Liu             handleGetEfficiencyResponse(asyncResp, ec1, value);
431ddceee07SGeorge Liu         });
432ddceee07SGeorge Liu }
433ddceee07SGeorge Liu 
434504af5a0SPatrick Williams inline void getEfficiencyPercent(
435504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
436ddceee07SGeorge Liu {
437ddceee07SGeorge Liu     constexpr std::array<std::string_view, 1> efficiencyIntf = {
438ddceee07SGeorge Liu         "xyz.openbmc_project.Control.PowerSupplyAttributes"};
439ddceee07SGeorge Liu 
440ddceee07SGeorge Liu     dbus::utility::getSubTree(
441ddceee07SGeorge Liu         "/xyz/openbmc_project", 0, efficiencyIntf,
442ddceee07SGeorge Liu         [asyncResp](const boost::system::error_code& ec,
443ddceee07SGeorge Liu                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
444ddceee07SGeorge Liu             handlePowerSupplyAttributesSubTreeResponse(asyncResp, ec, subtree);
445ddceee07SGeorge Liu         });
446ddceee07SGeorge Liu }
447ddceee07SGeorge Liu 
448bd79bce8SPatrick Williams inline void doPowerSupplyGet(
449bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
450bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& powerSupplyId,
4513e42a329SLakshmi Yadlapati     const std::string& powerSupplyPath, const std::string& service)
45200ef5dc6SGeorge Liu {
453193582b6SMyung Bae     if (powerSupplyPath.empty() || service.empty())
454193582b6SMyung Bae     {
455193582b6SMyung Bae         BMCWEB_LOG_WARNING("PowerSupply not found");
456193582b6SMyung Bae         messages::resourceNotFound(asyncResp->res, "PowerSupply",
457193582b6SMyung Bae                                    powerSupplyId);
458193582b6SMyung Bae         return;
459193582b6SMyung Bae     }
460193582b6SMyung Bae 
46100ef5dc6SGeorge Liu     asyncResp->res.addHeader(
46200ef5dc6SGeorge Liu         boost::beast::http::field::link,
46300ef5dc6SGeorge Liu         "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
4643e42a329SLakshmi Yadlapati     asyncResp->res.jsonValue["@odata.type"] = "#PowerSupply.v1_5_0.PowerSupply";
46500ef5dc6SGeorge Liu     asyncResp->res.jsonValue["Name"] = "Power Supply";
46600ef5dc6SGeorge Liu     asyncResp->res.jsonValue["Id"] = powerSupplyId;
46700ef5dc6SGeorge Liu     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
4683e42a329SLakshmi Yadlapati         "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
4693e42a329SLakshmi Yadlapati         powerSupplyId);
47034dfcb94SGeorge Liu 
4713e42a329SLakshmi Yadlapati     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
472539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
47334dfcb94SGeorge Liu 
4743e42a329SLakshmi Yadlapati     getPowerSupplyState(asyncResp, service, powerSupplyPath);
4753e42a329SLakshmi Yadlapati     getPowerSupplyHealth(asyncResp, service, powerSupplyPath);
4763e42a329SLakshmi Yadlapati     getPowerSupplyAsset(asyncResp, service, powerSupplyPath);
4773e42a329SLakshmi Yadlapati     getPowerSupplyFirmwareVersion(asyncResp, service, powerSupplyPath);
4783e42a329SLakshmi Yadlapati     getPowerSupplyLocation(asyncResp, service, powerSupplyPath);
479ddceee07SGeorge Liu     getEfficiencyPercent(asyncResp);
4807066dc58SMyung Bae     getLocationIndicatorActive(asyncResp, powerSupplyPath);
48100ef5dc6SGeorge Liu }
48200ef5dc6SGeorge Liu 
483bd79bce8SPatrick Williams inline void handlePowerSupplyHead(
484bd79bce8SPatrick Williams     App& app, const crow::Request& req,
48500ef5dc6SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
486bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& powerSupplyId)
48700ef5dc6SGeorge Liu {
48800ef5dc6SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
48900ef5dc6SGeorge Liu     {
49000ef5dc6SGeorge Liu         return;
49100ef5dc6SGeorge Liu     }
49200ef5dc6SGeorge Liu 
49300ef5dc6SGeorge Liu     // Get the correct Path and Service that match the input parameters
494bd79bce8SPatrick Williams     getValidPowerSupplyPath(
4953e42a329SLakshmi Yadlapati         asyncResp, chassisId, powerSupplyId,
496193582b6SMyung Bae         [asyncResp, powerSupplyId](const std::string& powerSupplyPath,
497193582b6SMyung Bae                                    const std::string& service) {
498193582b6SMyung Bae             if (powerSupplyPath.empty() || service.empty())
499193582b6SMyung Bae             {
500193582b6SMyung Bae                 BMCWEB_LOG_WARNING("PowerSupply not found");
501193582b6SMyung Bae                 messages::resourceNotFound(asyncResp->res, "PowerSupply",
502193582b6SMyung Bae                                            powerSupplyId);
503193582b6SMyung Bae                 return;
504193582b6SMyung Bae             }
50500ef5dc6SGeorge Liu             asyncResp->res.addHeader(
50600ef5dc6SGeorge Liu                 boost::beast::http::field::link,
50700ef5dc6SGeorge Liu                 "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
50800ef5dc6SGeorge Liu         });
50900ef5dc6SGeorge Liu }
51000ef5dc6SGeorge Liu 
511bd79bce8SPatrick Williams inline void handlePowerSupplyGet(
512bd79bce8SPatrick Williams     App& app, const crow::Request& req,
51300ef5dc6SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
514bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& powerSupplyId)
51500ef5dc6SGeorge Liu {
51600ef5dc6SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
51700ef5dc6SGeorge Liu     {
51800ef5dc6SGeorge Liu         return;
51900ef5dc6SGeorge Liu     }
5203e42a329SLakshmi Yadlapati     getValidPowerSupplyPath(
5213e42a329SLakshmi Yadlapati         asyncResp, chassisId, powerSupplyId,
52200ef5dc6SGeorge Liu         std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId));
52300ef5dc6SGeorge Liu }
52400ef5dc6SGeorge Liu 
5257066dc58SMyung Bae inline void doPatchPowerSupply(
5267066dc58SMyung Bae     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5277066dc58SMyung Bae     const bool locationIndicatorActive, const std::string& powerSupplyPath,
5287066dc58SMyung Bae     const std::string& /*service*/)
5297066dc58SMyung Bae {
5307066dc58SMyung Bae     setLocationIndicatorActive(asyncResp, powerSupplyPath,
5317066dc58SMyung Bae                                locationIndicatorActive);
5327066dc58SMyung Bae }
5337066dc58SMyung Bae 
5347066dc58SMyung Bae inline void handlePowerSupplyPatch(
5357066dc58SMyung Bae     App& app, const crow::Request& req,
5367066dc58SMyung Bae     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5377066dc58SMyung Bae     const std::string& chassisId, const std::string& powerSupplyId)
5387066dc58SMyung Bae {
5397066dc58SMyung Bae     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
5407066dc58SMyung Bae     {
5417066dc58SMyung Bae         return;
5427066dc58SMyung Bae     }
5437066dc58SMyung Bae 
5447066dc58SMyung Bae     std::optional<bool> locationIndicatorActive;
5457066dc58SMyung Bae     if (!json_util::readJsonPatch(                             //
5467066dc58SMyung Bae             req, asyncResp->res,                               //
5477066dc58SMyung Bae             "LocationIndicatorActive", locationIndicatorActive //
5487066dc58SMyung Bae             ))
5497066dc58SMyung Bae     {
5507066dc58SMyung Bae         return;
5517066dc58SMyung Bae     }
5527066dc58SMyung Bae 
5537066dc58SMyung Bae     if (locationIndicatorActive)
5547066dc58SMyung Bae     {
5557066dc58SMyung Bae         // Get the correct power supply Path that match the input parameters
5567066dc58SMyung Bae         getValidPowerSupplyPath(asyncResp, chassisId, powerSupplyId,
5577066dc58SMyung Bae                                 std::bind_front(doPatchPowerSupply, asyncResp,
5587066dc58SMyung Bae                                                 *locationIndicatorActive));
5597066dc58SMyung Bae     }
5607066dc58SMyung Bae }
5617066dc58SMyung Bae 
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)));
5757066dc58SMyung Bae 
5767066dc58SMyung Bae     BMCWEB_ROUTE(
5777066dc58SMyung Bae         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
5787066dc58SMyung Bae         .privileges(redfish::privileges::patchPowerSupply)
5797066dc58SMyung Bae         .methods(boost::beast::http::verb::patch)(
5807066dc58SMyung Bae             std::bind_front(handlePowerSupplyPatch, std::ref(app)));
58100ef5dc6SGeorge Liu }
58200ef5dc6SGeorge Liu 
583a7210020SGeorge Liu } // namespace redfish
584