xref: /openbmc/bmcweb/features/redfish/lib/power_supply.hpp (revision 7066dc58dd7c3b56e0f224458e9190be8d758771)
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"
11*7066dc58SMyung Bae #include "led.hpp"
12d7857201SEd Tanous #include "logging.hpp"
13a7210020SGeorge Liu #include "query.hpp"
14a7210020SGeorge Liu #include "registries/privilege_registry.hpp"
15a7210020SGeorge Liu #include "utils/chassis_utils.hpp"
162b45fb3bSGeorge Liu #include "utils/dbus_utils.hpp"
17*7066dc58SMyung Bae #include "utils/json_utils.hpp"
18b5190062SHieu Huynh #include "utils/time_utils.hpp"
19a7210020SGeorge Liu 
20d7857201SEd Tanous #include <asm-generic/errno.h>
21d7857201SEd Tanous 
22d7857201SEd Tanous #include <boost/beast/http/field.hpp>
23d7857201SEd Tanous #include <boost/beast/http/verb.hpp>
2434dfcb94SGeorge Liu #include <boost/system/error_code.hpp>
25ef4c65b7SEd Tanous #include <boost/url/format.hpp>
26d7857201SEd Tanous #include <nlohmann/json.hpp>
27d7857201SEd Tanous #include <sdbusplus/unpack_properties.hpp>
28ef4c65b7SEd Tanous 
29d7857201SEd Tanous #include <array>
30d7857201SEd Tanous #include <cstdint>
31d7857201SEd Tanous #include <functional>
32a7210020SGeorge Liu #include <memory>
33a7210020SGeorge Liu #include <optional>
34a7210020SGeorge Liu #include <string>
35d7857201SEd Tanous #include <string_view>
36d7857201SEd Tanous #include <utility>
37a7210020SGeorge Liu 
38a7210020SGeorge Liu namespace redfish
39a7210020SGeorge Liu {
40a7210020SGeorge Liu 
41788fe6cfSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> powerSupplyInterface = {
42788fe6cfSLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PowerSupply"};
43788fe6cfSLakshmi Yadlapati 
44788fe6cfSLakshmi Yadlapati inline void updatePowerSupplyList(
45788fe6cfSLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4600ef5dc6SGeorge Liu     const std::string& chassisId,
47788fe6cfSLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& powerSupplyPaths)
48788fe6cfSLakshmi Yadlapati {
49788fe6cfSLakshmi Yadlapati     nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"];
50788fe6cfSLakshmi Yadlapati     for (const std::string& powerSupplyPath : powerSupplyPaths)
51a7210020SGeorge Liu     {
5200ef5dc6SGeorge Liu         std::string powerSupplyName =
5300ef5dc6SGeorge Liu             sdbusplus::message::object_path(powerSupplyPath).filename();
5400ef5dc6SGeorge Liu         if (powerSupplyName.empty())
5500ef5dc6SGeorge Liu         {
56788fe6cfSLakshmi Yadlapati             continue;
5700ef5dc6SGeorge Liu         }
5800ef5dc6SGeorge Liu 
5900ef5dc6SGeorge Liu         nlohmann::json item = nlohmann::json::object();
6000ef5dc6SGeorge Liu         item["@odata.id"] = boost::urls::format(
6100ef5dc6SGeorge Liu             "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
6200ef5dc6SGeorge Liu             powerSupplyName);
6300ef5dc6SGeorge Liu 
6400ef5dc6SGeorge Liu         powerSupplyList.emplace_back(std::move(item));
65788fe6cfSLakshmi Yadlapati     }
6600ef5dc6SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size();
67a7210020SGeorge Liu }
68a7210020SGeorge Liu 
693e42a329SLakshmi Yadlapati inline void doPowerSupplyCollection(
703e42a329SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
713e42a329SLakshmi Yadlapati     const std::string& chassisId, const boost::system::error_code& ec,
723e42a329SLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths)
73a7210020SGeorge Liu {
743e42a329SLakshmi Yadlapati     if (ec)
75a7210020SGeorge Liu     {
76193582b6SMyung Bae         if (ec.value() == boost::system::errc::io_error)
77193582b6SMyung Bae         {
78193582b6SMyung Bae             BMCWEB_LOG_WARNING("Chassis not found");
79193582b6SMyung Bae             messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
80193582b6SMyung Bae             return;
81193582b6SMyung Bae         }
823e42a329SLakshmi Yadlapati         if (ec.value() != EBADR)
833e42a329SLakshmi Yadlapati         {
843e42a329SLakshmi Yadlapati             BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
853e42a329SLakshmi Yadlapati             messages::internalError(asyncResp->res);
863e42a329SLakshmi Yadlapati         }
87a7210020SGeorge Liu         return;
88a7210020SGeorge Liu     }
89a7210020SGeorge Liu     asyncResp->res.addHeader(
90a7210020SGeorge Liu         boost::beast::http::field::link,
91a7210020SGeorge Liu         "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
92a7210020SGeorge Liu     asyncResp->res.jsonValue["@odata.type"] =
93a7210020SGeorge Liu         "#PowerSupplyCollection.PowerSupplyCollection";
94a7210020SGeorge Liu     asyncResp->res.jsonValue["Name"] = "Power Supply Collection";
95ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
96ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId);
97a7210020SGeorge Liu     asyncResp->res.jsonValue["Description"] =
98a7210020SGeorge Liu         "The collection of PowerSupply resource instances.";
997a2bb2c9SGeorge Liu     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
1007a2bb2c9SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = 0;
101a7210020SGeorge Liu 
102788fe6cfSLakshmi Yadlapati     updatePowerSupplyList(asyncResp, chassisId, subtreePaths);
103a7210020SGeorge Liu }
104a7210020SGeorge Liu 
105a7210020SGeorge Liu inline void handlePowerSupplyCollectionHead(
106a7210020SGeorge Liu     App& app, const crow::Request& req,
107a7210020SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
108a7210020SGeorge Liu     const std::string& chassisId)
109a7210020SGeorge Liu {
110a7210020SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
111a7210020SGeorge Liu     {
112a7210020SGeorge Liu         return;
113a7210020SGeorge Liu     }
114a7210020SGeorge Liu 
115a7210020SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
116a7210020SGeorge Liu         asyncResp, chassisId,
117a7210020SGeorge Liu         [asyncResp,
118a7210020SGeorge Liu          chassisId](const std::optional<std::string>& validChassisPath) {
119a7210020SGeorge Liu             if (!validChassisPath)
120a7210020SGeorge Liu             {
121193582b6SMyung Bae                 BMCWEB_LOG_WARNING("Chassis not found");
122bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res, "Chassis",
123bd79bce8SPatrick Williams                                            chassisId);
124a7210020SGeorge Liu                 return;
125a7210020SGeorge Liu             }
126a7210020SGeorge Liu             asyncResp->res.addHeader(
127a7210020SGeorge Liu                 boost::beast::http::field::link,
128a7210020SGeorge Liu                 "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
129a7210020SGeorge Liu         });
130a7210020SGeorge Liu }
131a7210020SGeorge Liu 
132a7210020SGeorge Liu inline void handlePowerSupplyCollectionGet(
133a7210020SGeorge Liu     App& app, const crow::Request& req,
134a7210020SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
135a7210020SGeorge Liu     const std::string& chassisId)
136a7210020SGeorge Liu {
137a7210020SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
138a7210020SGeorge Liu     {
139a7210020SGeorge Liu         return;
140a7210020SGeorge Liu     }
141a7210020SGeorge Liu 
1423e42a329SLakshmi Yadlapati     const std::string reqpath = "/xyz/openbmc_project/inventory";
1433e42a329SLakshmi Yadlapati 
1443e42a329SLakshmi Yadlapati     dbus::utility::getAssociatedSubTreePathsById(
1453f95a277SMyung Bae         chassisId, reqpath, chassisInterfaces, "powered_by",
1463e42a329SLakshmi Yadlapati         powerSupplyInterface,
1473e42a329SLakshmi Yadlapati         [asyncResp, chassisId](
1483e42a329SLakshmi Yadlapati             const boost::system::error_code& ec,
1493e42a329SLakshmi Yadlapati             const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
1503e42a329SLakshmi Yadlapati             doPowerSupplyCollection(asyncResp, chassisId, ec, subtreePaths);
1513e42a329SLakshmi Yadlapati         });
152a7210020SGeorge Liu }
153a7210020SGeorge Liu 
154a7210020SGeorge Liu inline void requestRoutesPowerSupplyCollection(App& app)
155a7210020SGeorge Liu {
156a7210020SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
157a7210020SGeorge Liu         .privileges(redfish::privileges::headPowerSupplyCollection)
158a7210020SGeorge Liu         .methods(boost::beast::http::verb::head)(
159a7210020SGeorge Liu             std::bind_front(handlePowerSupplyCollectionHead, std::ref(app)));
160a7210020SGeorge Liu 
161a7210020SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
162a7210020SGeorge Liu         .privileges(redfish::privileges::getPowerSupplyCollection)
163a7210020SGeorge Liu         .methods(boost::beast::http::verb::get)(
164a7210020SGeorge Liu             std::bind_front(handlePowerSupplyCollectionGet, std::ref(app)));
165a7210020SGeorge Liu }
166a7210020SGeorge Liu 
1673e42a329SLakshmi Yadlapati inline void afterGetValidPowerSupplyPath(
16834dfcb94SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1693e42a329SLakshmi Yadlapati     const std::string& powerSupplyId, const boost::system::error_code& ec,
1703e42a329SLakshmi Yadlapati     const dbus::utility::MapperGetSubTreeResponse& subtree,
1713e42a329SLakshmi Yadlapati     const std::function<void(const std::string& powerSupplyPath,
1723e42a329SLakshmi Yadlapati                              const std::string& service)>& callback)
17300ef5dc6SGeorge Liu {
17400ef5dc6SGeorge Liu     if (ec)
17500ef5dc6SGeorge Liu     {
176193582b6SMyung Bae         if (ec.value() == boost::system::errc::io_error)
177193582b6SMyung Bae         {
178193582b6SMyung Bae             // Not found
179193582b6SMyung Bae             callback(std::string(), std::string());
180193582b6SMyung Bae             return;
181193582b6SMyung Bae         }
18200ef5dc6SGeorge Liu         if (ec.value() != EBADR)
18300ef5dc6SGeorge Liu         {
1843e42a329SLakshmi Yadlapati             BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
18500ef5dc6SGeorge Liu             messages::internalError(asyncResp->res);
186193582b6SMyung Bae             return;
1873e42a329SLakshmi Yadlapati         }
188193582b6SMyung Bae         callback(std::string(), std::string());
18900ef5dc6SGeorge Liu         return;
19000ef5dc6SGeorge Liu     }
1913e42a329SLakshmi Yadlapati     for (const auto& [objectPath, service] : subtree)
19200ef5dc6SGeorge Liu     {
1933e42a329SLakshmi Yadlapati         sdbusplus::message::object_path path(objectPath);
194d8e2b618SMyung Bae         if (path.filename() == powerSupplyId)
19500ef5dc6SGeorge Liu         {
1963e42a329SLakshmi Yadlapati             callback(path, service.begin()->first);
19700ef5dc6SGeorge Liu             return;
19800ef5dc6SGeorge Liu         }
19900ef5dc6SGeorge Liu     }
20000ef5dc6SGeorge Liu 
20162598e31SEd Tanous     BMCWEB_LOG_WARNING("Power supply not found: {}", powerSupplyId);
2023e42a329SLakshmi Yadlapati     messages::resourceNotFound(asyncResp->res, "PowerSupplies", powerSupplyId);
20300ef5dc6SGeorge Liu }
2043e42a329SLakshmi Yadlapati 
2053e42a329SLakshmi Yadlapati inline void getValidPowerSupplyPath(
2063e42a329SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2073e42a329SLakshmi Yadlapati     const std::string& chassisId, const std::string& powerSupplyId,
2083e42a329SLakshmi Yadlapati     std::function<void(const std::string& powerSupplyPath,
2093e42a329SLakshmi Yadlapati                        const std::string& service)>&& callback)
2103e42a329SLakshmi Yadlapati {
2113e42a329SLakshmi Yadlapati     const std::string reqpath = "/xyz/openbmc_project/inventory";
2123e42a329SLakshmi Yadlapati 
2133e42a329SLakshmi Yadlapati     dbus::utility::getAssociatedSubTreeById(
2143f95a277SMyung Bae         chassisId, reqpath, chassisInterfaces, "powered_by",
2153e42a329SLakshmi Yadlapati         powerSupplyInterface,
2163e42a329SLakshmi Yadlapati         [asyncResp, chassisId, powerSupplyId, callback{std::move(callback)}](
2173e42a329SLakshmi Yadlapati             const boost::system::error_code& ec,
2183e42a329SLakshmi Yadlapati             const dbus::utility::MapperGetSubTreeResponse& subtree) {
2193e42a329SLakshmi Yadlapati             afterGetValidPowerSupplyPath(asyncResp, powerSupplyId, ec, subtree,
2203e42a329SLakshmi Yadlapati                                          callback);
22100ef5dc6SGeorge Liu         });
22200ef5dc6SGeorge Liu }
22300ef5dc6SGeorge Liu 
224504af5a0SPatrick Williams inline void getPowerSupplyState(
225504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
22634dfcb94SGeorge Liu     const std::string& service, const std::string& path)
22734dfcb94SGeorge Liu {
228deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
229deae6a78SEd Tanous         service, path, "xyz.openbmc_project.Inventory.Item", "Present",
23034dfcb94SGeorge Liu         [asyncResp](const boost::system::error_code& ec, const bool value) {
23134dfcb94SGeorge Liu             if (ec)
23234dfcb94SGeorge Liu             {
23334dfcb94SGeorge Liu                 if (ec.value() != EBADR)
23434dfcb94SGeorge Liu                 {
23562598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for State {}",
23662598e31SEd Tanous                                      ec.value());
23734dfcb94SGeorge Liu                     messages::internalError(asyncResp->res);
23834dfcb94SGeorge Liu                 }
23934dfcb94SGeorge Liu                 return;
24034dfcb94SGeorge Liu             }
24134dfcb94SGeorge Liu 
24234dfcb94SGeorge Liu             if (!value)
24334dfcb94SGeorge Liu             {
244539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
245539d8c6bSEd Tanous                     resource::State::Absent;
24634dfcb94SGeorge Liu             }
24734dfcb94SGeorge Liu         });
24834dfcb94SGeorge Liu }
24934dfcb94SGeorge Liu 
250504af5a0SPatrick Williams inline void getPowerSupplyHealth(
251504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
25234dfcb94SGeorge Liu     const std::string& service, const std::string& path)
25334dfcb94SGeorge Liu {
254deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
255deae6a78SEd Tanous         service, path, "xyz.openbmc_project.State.Decorator.OperationalStatus",
256deae6a78SEd Tanous         "Functional",
25734dfcb94SGeorge Liu         [asyncResp](const boost::system::error_code& ec, const bool value) {
25834dfcb94SGeorge Liu             if (ec)
25934dfcb94SGeorge Liu             {
26034dfcb94SGeorge Liu                 if (ec.value() != EBADR)
26134dfcb94SGeorge Liu                 {
26262598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Health {}",
26362598e31SEd Tanous                                      ec.value());
26434dfcb94SGeorge Liu                     messages::internalError(asyncResp->res);
26534dfcb94SGeorge Liu                 }
26634dfcb94SGeorge Liu                 return;
26734dfcb94SGeorge Liu             }
26834dfcb94SGeorge Liu 
26934dfcb94SGeorge Liu             if (!value)
27034dfcb94SGeorge Liu             {
271539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["Health"] =
272539d8c6bSEd Tanous                     resource::Health::Critical;
27334dfcb94SGeorge Liu             }
27434dfcb94SGeorge Liu         });
27534dfcb94SGeorge Liu }
27634dfcb94SGeorge Liu 
277504af5a0SPatrick Williams inline void getPowerSupplyAsset(
278504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2792b45fb3bSGeorge Liu     const std::string& service, const std::string& path)
2802b45fb3bSGeorge Liu {
281deae6a78SEd Tanous     dbus::utility::getAllProperties(
282deae6a78SEd Tanous         service, path, "xyz.openbmc_project.Inventory.Decorator.Asset",
2832b45fb3bSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
2842b45fb3bSGeorge Liu                     const dbus::utility::DBusPropertiesMap& propertiesList) {
2852b45fb3bSGeorge Liu             if (ec)
2862b45fb3bSGeorge Liu             {
2872b45fb3bSGeorge Liu                 if (ec.value() != EBADR)
2882b45fb3bSGeorge Liu                 {
28962598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Asset {}",
29062598e31SEd Tanous                                      ec.value());
2912b45fb3bSGeorge Liu                     messages::internalError(asyncResp->res);
2922b45fb3bSGeorge Liu                 }
2932b45fb3bSGeorge Liu                 return;
2942b45fb3bSGeorge Liu             }
2952b45fb3bSGeorge Liu 
2962b45fb3bSGeorge Liu             const std::string* partNumber = nullptr;
2972b45fb3bSGeorge Liu             const std::string* serialNumber = nullptr;
2982b45fb3bSGeorge Liu             const std::string* manufacturer = nullptr;
2992b45fb3bSGeorge Liu             const std::string* model = nullptr;
3002b45fb3bSGeorge Liu             const std::string* sparePartNumber = nullptr;
301b5190062SHieu Huynh             const std::string* buildDate = nullptr;
3022b45fb3bSGeorge Liu 
3032b45fb3bSGeorge Liu             const bool success = sdbusplus::unpackPropertiesNoThrow(
3042b45fb3bSGeorge Liu                 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
3052b45fb3bSGeorge Liu                 partNumber, "SerialNumber", serialNumber, "Manufacturer",
306bd79bce8SPatrick Williams                 manufacturer, "Model", model, "SparePartNumber",
307b5190062SHieu Huynh                 sparePartNumber, "BuildDate", buildDate);
3082b45fb3bSGeorge Liu 
3092b45fb3bSGeorge Liu             if (!success)
3102b45fb3bSGeorge Liu             {
3112b45fb3bSGeorge Liu                 messages::internalError(asyncResp->res);
3122b45fb3bSGeorge Liu                 return;
3132b45fb3bSGeorge Liu             }
3142b45fb3bSGeorge Liu 
3152b45fb3bSGeorge Liu             if (partNumber != nullptr)
3162b45fb3bSGeorge Liu             {
3172b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
3182b45fb3bSGeorge Liu             }
3192b45fb3bSGeorge Liu 
3202b45fb3bSGeorge Liu             if (serialNumber != nullptr)
3212b45fb3bSGeorge Liu             {
3222b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
3232b45fb3bSGeorge Liu             }
3242b45fb3bSGeorge Liu 
3252b45fb3bSGeorge Liu             if (manufacturer != nullptr)
3262b45fb3bSGeorge Liu             {
3272b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
3282b45fb3bSGeorge Liu             }
3292b45fb3bSGeorge Liu 
3302b45fb3bSGeorge Liu             if (model != nullptr)
3312b45fb3bSGeorge Liu             {
3322b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["Model"] = *model;
3332b45fb3bSGeorge Liu             }
3342b45fb3bSGeorge Liu 
3352b45fb3bSGeorge Liu             // SparePartNumber is optional on D-Bus so skip if it is empty
3362b45fb3bSGeorge Liu             if (sparePartNumber != nullptr && !sparePartNumber->empty())
3372b45fb3bSGeorge Liu             {
3382b45fb3bSGeorge Liu                 asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
3392b45fb3bSGeorge Liu             }
340b5190062SHieu Huynh 
341b5190062SHieu Huynh             if (buildDate != nullptr)
342b5190062SHieu Huynh             {
343b5190062SHieu Huynh                 time_utils::productionDateReport(asyncResp->res, *buildDate);
344b5190062SHieu Huynh             }
3452b45fb3bSGeorge Liu         });
3462b45fb3bSGeorge Liu }
3472b45fb3bSGeorge Liu 
348a0dba87bSGeorge Liu inline void getPowerSupplyFirmwareVersion(
349a0dba87bSGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
350a0dba87bSGeorge Liu     const std::string& service, const std::string& path)
351a0dba87bSGeorge Liu {
352deae6a78SEd Tanous     dbus::utility::getProperty<std::string>(
353deae6a78SEd Tanous         service, path, "xyz.openbmc_project.Software.Version", "Version",
354a0dba87bSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
355a0dba87bSGeorge Liu                     const std::string& value) {
356a0dba87bSGeorge Liu             if (ec)
357a0dba87bSGeorge Liu             {
358a0dba87bSGeorge Liu                 if (ec.value() != EBADR)
359a0dba87bSGeorge Liu                 {
360bd79bce8SPatrick Williams                     BMCWEB_LOG_ERROR(
361bd79bce8SPatrick Williams                         "DBUS response error for FirmwareVersion {}",
36262598e31SEd Tanous                         ec.value());
363a0dba87bSGeorge Liu                     messages::internalError(asyncResp->res);
364a0dba87bSGeorge Liu                 }
365a0dba87bSGeorge Liu                 return;
366a0dba87bSGeorge Liu             }
367a0dba87bSGeorge Liu             asyncResp->res.jsonValue["FirmwareVersion"] = value;
368a0dba87bSGeorge Liu         });
369a0dba87bSGeorge Liu }
370a0dba87bSGeorge Liu 
371504af5a0SPatrick Williams inline void getPowerSupplyLocation(
372504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
37344845e5fSGeorge Liu     const std::string& service, const std::string& path)
37444845e5fSGeorge Liu {
375deae6a78SEd Tanous     dbus::utility::getProperty<std::string>(
376deae6a78SEd Tanous         service, path, "xyz.openbmc_project.Inventory.Decorator.LocationCode",
377deae6a78SEd Tanous         "LocationCode",
37844845e5fSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
37944845e5fSGeorge Liu                     const std::string& value) {
38044845e5fSGeorge Liu             if (ec)
38144845e5fSGeorge Liu             {
38244845e5fSGeorge Liu                 if (ec.value() != EBADR)
38344845e5fSGeorge Liu                 {
38462598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Location {}",
38562598e31SEd Tanous                                      ec.value());
38644845e5fSGeorge Liu                     messages::internalError(asyncResp->res);
38744845e5fSGeorge Liu                 }
38844845e5fSGeorge Liu                 return;
38944845e5fSGeorge Liu             }
390bd79bce8SPatrick Williams             asyncResp->res
391bd79bce8SPatrick Williams                 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = value;
39244845e5fSGeorge Liu         });
39344845e5fSGeorge Liu }
39444845e5fSGeorge Liu 
395ddceee07SGeorge Liu inline void handleGetEfficiencyResponse(
396ddceee07SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
397ddceee07SGeorge Liu     const boost::system::error_code& ec, uint32_t value)
398ddceee07SGeorge Liu {
399ddceee07SGeorge Liu     if (ec)
400ddceee07SGeorge Liu     {
401ddceee07SGeorge Liu         if (ec.value() != EBADR)
402ddceee07SGeorge Liu         {
40362598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for DeratingFactor {}",
40462598e31SEd Tanous                              ec.value());
405ddceee07SGeorge Liu             messages::internalError(asyncResp->res);
406ddceee07SGeorge Liu         }
407ddceee07SGeorge Liu         return;
408ddceee07SGeorge Liu     }
409ddceee07SGeorge Liu     // The PDI default value is 0, if it hasn't been set leave off
410ddceee07SGeorge Liu     if (value == 0)
411ddceee07SGeorge Liu     {
412ddceee07SGeorge Liu         return;
413ddceee07SGeorge Liu     }
414ddceee07SGeorge Liu 
415ddceee07SGeorge Liu     nlohmann::json::array_t efficiencyRatings;
416ddceee07SGeorge Liu     nlohmann::json::object_t efficiencyPercent;
417ddceee07SGeorge Liu     efficiencyPercent["EfficiencyPercent"] = value;
418ddceee07SGeorge Liu     efficiencyRatings.emplace_back(std::move(efficiencyPercent));
419ddceee07SGeorge Liu     asyncResp->res.jsonValue["EfficiencyRatings"] =
420ddceee07SGeorge Liu         std::move(efficiencyRatings);
421ddceee07SGeorge Liu }
422ddceee07SGeorge Liu 
423ddceee07SGeorge Liu inline void handlePowerSupplyAttributesSubTreeResponse(
424ddceee07SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
425ddceee07SGeorge Liu     const boost::system::error_code& ec,
426ddceee07SGeorge Liu     const dbus::utility::MapperGetSubTreeResponse& subtree)
427ddceee07SGeorge Liu {
428ddceee07SGeorge Liu     if (ec)
429ddceee07SGeorge Liu     {
430ddceee07SGeorge Liu         if (ec.value() != EBADR)
431ddceee07SGeorge Liu         {
43262598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for EfficiencyPercent {}",
43362598e31SEd Tanous                              ec.value());
434ddceee07SGeorge Liu             messages::internalError(asyncResp->res);
435ddceee07SGeorge Liu         }
436ddceee07SGeorge Liu         return;
437ddceee07SGeorge Liu     }
438ddceee07SGeorge Liu 
439ddceee07SGeorge Liu     if (subtree.empty())
440ddceee07SGeorge Liu     {
44162598e31SEd Tanous         BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
442ddceee07SGeorge Liu         return;
443ddceee07SGeorge Liu     }
444ddceee07SGeorge Liu 
445ddceee07SGeorge Liu     if (subtree.size() != 1)
446ddceee07SGeorge Liu     {
44762598e31SEd Tanous         BMCWEB_LOG_ERROR(
44862598e31SEd Tanous             "Unexpected number of paths returned by getSubTree: {}",
44962598e31SEd Tanous             subtree.size());
450ddceee07SGeorge Liu         messages::internalError(asyncResp->res);
451ddceee07SGeorge Liu         return;
452ddceee07SGeorge Liu     }
453ddceee07SGeorge Liu 
454ddceee07SGeorge Liu     const auto& [path, serviceMap] = *subtree.begin();
455ddceee07SGeorge Liu     const auto& [service, interfaces] = *serviceMap.begin();
456deae6a78SEd Tanous     dbus::utility::getProperty<uint32_t>(
457deae6a78SEd Tanous         service, path, "xyz.openbmc_project.Control.PowerSupplyAttributes",
458deae6a78SEd Tanous         "DeratingFactor",
459ddceee07SGeorge Liu         [asyncResp](const boost::system::error_code& ec1, uint32_t value) {
460ddceee07SGeorge Liu             handleGetEfficiencyResponse(asyncResp, ec1, value);
461ddceee07SGeorge Liu         });
462ddceee07SGeorge Liu }
463ddceee07SGeorge Liu 
464504af5a0SPatrick Williams inline void getEfficiencyPercent(
465504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
466ddceee07SGeorge Liu {
467ddceee07SGeorge Liu     constexpr std::array<std::string_view, 1> efficiencyIntf = {
468ddceee07SGeorge Liu         "xyz.openbmc_project.Control.PowerSupplyAttributes"};
469ddceee07SGeorge Liu 
470ddceee07SGeorge Liu     dbus::utility::getSubTree(
471ddceee07SGeorge Liu         "/xyz/openbmc_project", 0, efficiencyIntf,
472ddceee07SGeorge Liu         [asyncResp](const boost::system::error_code& ec,
473ddceee07SGeorge Liu                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
474ddceee07SGeorge Liu             handlePowerSupplyAttributesSubTreeResponse(asyncResp, ec, subtree);
475ddceee07SGeorge Liu         });
476ddceee07SGeorge Liu }
477ddceee07SGeorge Liu 
478bd79bce8SPatrick Williams inline void doPowerSupplyGet(
479bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
480bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& powerSupplyId,
4813e42a329SLakshmi Yadlapati     const std::string& powerSupplyPath, const std::string& service)
48200ef5dc6SGeorge Liu {
483193582b6SMyung Bae     if (powerSupplyPath.empty() || service.empty())
484193582b6SMyung Bae     {
485193582b6SMyung Bae         BMCWEB_LOG_WARNING("PowerSupply not found");
486193582b6SMyung Bae         messages::resourceNotFound(asyncResp->res, "PowerSupply",
487193582b6SMyung Bae                                    powerSupplyId);
488193582b6SMyung Bae         return;
489193582b6SMyung Bae     }
490193582b6SMyung Bae 
49100ef5dc6SGeorge Liu     asyncResp->res.addHeader(
49200ef5dc6SGeorge Liu         boost::beast::http::field::link,
49300ef5dc6SGeorge Liu         "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
4943e42a329SLakshmi Yadlapati     asyncResp->res.jsonValue["@odata.type"] = "#PowerSupply.v1_5_0.PowerSupply";
49500ef5dc6SGeorge Liu     asyncResp->res.jsonValue["Name"] = "Power Supply";
49600ef5dc6SGeorge Liu     asyncResp->res.jsonValue["Id"] = powerSupplyId;
49700ef5dc6SGeorge Liu     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
4983e42a329SLakshmi Yadlapati         "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
4993e42a329SLakshmi Yadlapati         powerSupplyId);
50034dfcb94SGeorge Liu 
5013e42a329SLakshmi Yadlapati     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
502539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
50334dfcb94SGeorge Liu 
5043e42a329SLakshmi Yadlapati     getPowerSupplyState(asyncResp, service, powerSupplyPath);
5053e42a329SLakshmi Yadlapati     getPowerSupplyHealth(asyncResp, service, powerSupplyPath);
5063e42a329SLakshmi Yadlapati     getPowerSupplyAsset(asyncResp, service, powerSupplyPath);
5073e42a329SLakshmi Yadlapati     getPowerSupplyFirmwareVersion(asyncResp, service, powerSupplyPath);
5083e42a329SLakshmi Yadlapati     getPowerSupplyLocation(asyncResp, service, powerSupplyPath);
509ddceee07SGeorge Liu     getEfficiencyPercent(asyncResp);
510*7066dc58SMyung Bae     getLocationIndicatorActive(asyncResp, powerSupplyPath);
51100ef5dc6SGeorge Liu }
51200ef5dc6SGeorge Liu 
513bd79bce8SPatrick Williams inline void handlePowerSupplyHead(
514bd79bce8SPatrick Williams     App& app, const crow::Request& req,
51500ef5dc6SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
516bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& powerSupplyId)
51700ef5dc6SGeorge Liu {
51800ef5dc6SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
51900ef5dc6SGeorge Liu     {
52000ef5dc6SGeorge Liu         return;
52100ef5dc6SGeorge Liu     }
52200ef5dc6SGeorge Liu 
52300ef5dc6SGeorge Liu     // Get the correct Path and Service that match the input parameters
524bd79bce8SPatrick Williams     getValidPowerSupplyPath(
5253e42a329SLakshmi Yadlapati         asyncResp, chassisId, powerSupplyId,
526193582b6SMyung Bae         [asyncResp, powerSupplyId](const std::string& powerSupplyPath,
527193582b6SMyung Bae                                    const std::string& service) {
528193582b6SMyung Bae             if (powerSupplyPath.empty() || service.empty())
529193582b6SMyung Bae             {
530193582b6SMyung Bae                 BMCWEB_LOG_WARNING("PowerSupply not found");
531193582b6SMyung Bae                 messages::resourceNotFound(asyncResp->res, "PowerSupply",
532193582b6SMyung Bae                                            powerSupplyId);
533193582b6SMyung Bae                 return;
534193582b6SMyung Bae             }
53500ef5dc6SGeorge Liu             asyncResp->res.addHeader(
53600ef5dc6SGeorge Liu                 boost::beast::http::field::link,
53700ef5dc6SGeorge Liu                 "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
53800ef5dc6SGeorge Liu         });
53900ef5dc6SGeorge Liu }
54000ef5dc6SGeorge Liu 
541bd79bce8SPatrick Williams inline void handlePowerSupplyGet(
542bd79bce8SPatrick Williams     App& app, const crow::Request& req,
54300ef5dc6SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
544bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& powerSupplyId)
54500ef5dc6SGeorge Liu {
54600ef5dc6SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
54700ef5dc6SGeorge Liu     {
54800ef5dc6SGeorge Liu         return;
54900ef5dc6SGeorge Liu     }
5503e42a329SLakshmi Yadlapati     getValidPowerSupplyPath(
5513e42a329SLakshmi Yadlapati         asyncResp, chassisId, powerSupplyId,
55200ef5dc6SGeorge Liu         std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId));
55300ef5dc6SGeorge Liu }
55400ef5dc6SGeorge Liu 
555*7066dc58SMyung Bae inline void doPatchPowerSupply(
556*7066dc58SMyung Bae     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
557*7066dc58SMyung Bae     const bool locationIndicatorActive, const std::string& powerSupplyPath,
558*7066dc58SMyung Bae     const std::string& /*service*/)
559*7066dc58SMyung Bae {
560*7066dc58SMyung Bae     setLocationIndicatorActive(asyncResp, powerSupplyPath,
561*7066dc58SMyung Bae                                locationIndicatorActive);
562*7066dc58SMyung Bae }
563*7066dc58SMyung Bae 
564*7066dc58SMyung Bae inline void handlePowerSupplyPatch(
565*7066dc58SMyung Bae     App& app, const crow::Request& req,
566*7066dc58SMyung Bae     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
567*7066dc58SMyung Bae     const std::string& chassisId, const std::string& powerSupplyId)
568*7066dc58SMyung Bae {
569*7066dc58SMyung Bae     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
570*7066dc58SMyung Bae     {
571*7066dc58SMyung Bae         return;
572*7066dc58SMyung Bae     }
573*7066dc58SMyung Bae 
574*7066dc58SMyung Bae     std::optional<bool> locationIndicatorActive;
575*7066dc58SMyung Bae     if (!json_util::readJsonPatch(                             //
576*7066dc58SMyung Bae             req, asyncResp->res,                               //
577*7066dc58SMyung Bae             "LocationIndicatorActive", locationIndicatorActive //
578*7066dc58SMyung Bae             ))
579*7066dc58SMyung Bae     {
580*7066dc58SMyung Bae         return;
581*7066dc58SMyung Bae     }
582*7066dc58SMyung Bae 
583*7066dc58SMyung Bae     if (locationIndicatorActive)
584*7066dc58SMyung Bae     {
585*7066dc58SMyung Bae         // Get the correct power supply Path that match the input parameters
586*7066dc58SMyung Bae         getValidPowerSupplyPath(asyncResp, chassisId, powerSupplyId,
587*7066dc58SMyung Bae                                 std::bind_front(doPatchPowerSupply, asyncResp,
588*7066dc58SMyung Bae                                                 *locationIndicatorActive));
589*7066dc58SMyung Bae     }
590*7066dc58SMyung Bae }
591*7066dc58SMyung Bae 
59200ef5dc6SGeorge Liu inline void requestRoutesPowerSupply(App& app)
59300ef5dc6SGeorge Liu {
59400ef5dc6SGeorge Liu     BMCWEB_ROUTE(
59500ef5dc6SGeorge Liu         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
59600ef5dc6SGeorge Liu         .privileges(redfish::privileges::headPowerSupply)
59700ef5dc6SGeorge Liu         .methods(boost::beast::http::verb::head)(
59800ef5dc6SGeorge Liu             std::bind_front(handlePowerSupplyHead, std::ref(app)));
59900ef5dc6SGeorge Liu 
60000ef5dc6SGeorge Liu     BMCWEB_ROUTE(
60100ef5dc6SGeorge Liu         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
60200ef5dc6SGeorge Liu         .privileges(redfish::privileges::getPowerSupply)
60300ef5dc6SGeorge Liu         .methods(boost::beast::http::verb::get)(
60400ef5dc6SGeorge Liu             std::bind_front(handlePowerSupplyGet, std::ref(app)));
605*7066dc58SMyung Bae 
606*7066dc58SMyung Bae     BMCWEB_ROUTE(
607*7066dc58SMyung Bae         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
608*7066dc58SMyung Bae         .privileges(redfish::privileges::patchPowerSupply)
609*7066dc58SMyung Bae         .methods(boost::beast::http::verb::patch)(
610*7066dc58SMyung Bae             std::bind_front(handlePowerSupplyPatch, std::ref(app)));
61100ef5dc6SGeorge Liu }
61200ef5dc6SGeorge Liu 
613a7210020SGeorge Liu } // namespace redfish
614