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