1a7210020SGeorge Liu #pragma once 2a7210020SGeorge Liu 3a7210020SGeorge Liu #include "app.hpp" 4a7210020SGeorge Liu #include "dbus_utility.hpp" 5539d8c6bSEd Tanous #include "generated/enums/resource.hpp" 6a7210020SGeorge Liu #include "query.hpp" 7a7210020SGeorge Liu #include "registries/privilege_registry.hpp" 8a7210020SGeorge Liu #include "utils/chassis_utils.hpp" 92b45fb3bSGeorge Liu #include "utils/dbus_utils.hpp" 102b45fb3bSGeorge Liu #include "utils/json_utils.hpp" 11a7210020SGeorge Liu 1234dfcb94SGeorge Liu #include <boost/system/error_code.hpp> 13ef4c65b7SEd Tanous #include <boost/url/format.hpp> 14ef4c65b7SEd Tanous 15a7210020SGeorge Liu #include <memory> 16a7210020SGeorge Liu #include <optional> 17a7210020SGeorge Liu #include <string> 18a7210020SGeorge Liu 19a7210020SGeorge Liu namespace redfish 20a7210020SGeorge Liu { 21a7210020SGeorge Liu 22788fe6cfSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> powerSupplyInterface = { 23788fe6cfSLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PowerSupply"}; 24788fe6cfSLakshmi Yadlapati 25788fe6cfSLakshmi Yadlapati inline void updatePowerSupplyList( 26788fe6cfSLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2700ef5dc6SGeorge Liu const std::string& chassisId, 28788fe6cfSLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& powerSupplyPaths) 29788fe6cfSLakshmi Yadlapati { 30788fe6cfSLakshmi Yadlapati nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"]; 31788fe6cfSLakshmi Yadlapati for (const std::string& powerSupplyPath : powerSupplyPaths) 32a7210020SGeorge Liu { 3300ef5dc6SGeorge Liu std::string powerSupplyName = 3400ef5dc6SGeorge Liu sdbusplus::message::object_path(powerSupplyPath).filename(); 3500ef5dc6SGeorge Liu if (powerSupplyName.empty()) 3600ef5dc6SGeorge Liu { 37788fe6cfSLakshmi Yadlapati continue; 3800ef5dc6SGeorge Liu } 3900ef5dc6SGeorge Liu 4000ef5dc6SGeorge Liu nlohmann::json item = nlohmann::json::object(); 4100ef5dc6SGeorge Liu item["@odata.id"] = boost::urls::format( 4200ef5dc6SGeorge Liu "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId, 4300ef5dc6SGeorge Liu powerSupplyName); 4400ef5dc6SGeorge Liu 4500ef5dc6SGeorge Liu powerSupplyList.emplace_back(std::move(item)); 46788fe6cfSLakshmi Yadlapati } 4700ef5dc6SGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size(); 48a7210020SGeorge Liu } 49a7210020SGeorge Liu 50*3e42a329SLakshmi Yadlapati inline void doPowerSupplyCollection( 51*3e42a329SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 52*3e42a329SLakshmi Yadlapati const std::string& chassisId, const boost::system::error_code& ec, 53*3e42a329SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) 54a7210020SGeorge Liu { 55*3e42a329SLakshmi Yadlapati if (ec) 56a7210020SGeorge Liu { 57*3e42a329SLakshmi Yadlapati if (ec.value() != EBADR) 58*3e42a329SLakshmi Yadlapati { 59*3e42a329SLakshmi Yadlapati BMCWEB_LOG_ERROR("DBUS response error{}", ec.value()); 60*3e42a329SLakshmi Yadlapati messages::internalError(asyncResp->res); 61*3e42a329SLakshmi Yadlapati } 62a7210020SGeorge Liu return; 63a7210020SGeorge Liu } 64a7210020SGeorge Liu asyncResp->res.addHeader( 65a7210020SGeorge Liu boost::beast::http::field::link, 66a7210020SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby"); 67a7210020SGeorge Liu asyncResp->res.jsonValue["@odata.type"] = 68a7210020SGeorge Liu "#PowerSupplyCollection.PowerSupplyCollection"; 69a7210020SGeorge Liu asyncResp->res.jsonValue["Name"] = "Power Supply Collection"; 70ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 71ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId); 72a7210020SGeorge Liu asyncResp->res.jsonValue["Description"] = 73a7210020SGeorge Liu "The collection of PowerSupply resource instances."; 747a2bb2c9SGeorge Liu asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 757a2bb2c9SGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = 0; 76a7210020SGeorge Liu 77788fe6cfSLakshmi Yadlapati updatePowerSupplyList(asyncResp, chassisId, subtreePaths); 78a7210020SGeorge Liu } 79a7210020SGeorge Liu 80a7210020SGeorge Liu inline void handlePowerSupplyCollectionHead( 81a7210020SGeorge Liu App& app, const crow::Request& req, 82a7210020SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 83a7210020SGeorge Liu const std::string& chassisId) 84a7210020SGeorge Liu { 85a7210020SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 86a7210020SGeorge Liu { 87a7210020SGeorge Liu return; 88a7210020SGeorge Liu } 89a7210020SGeorge Liu 90a7210020SGeorge Liu redfish::chassis_utils::getValidChassisPath( 91a7210020SGeorge Liu asyncResp, chassisId, 92a7210020SGeorge Liu [asyncResp, 93a7210020SGeorge Liu chassisId](const std::optional<std::string>& validChassisPath) { 94a7210020SGeorge Liu if (!validChassisPath) 95a7210020SGeorge Liu { 96bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Chassis", 97bd79bce8SPatrick Williams chassisId); 98a7210020SGeorge Liu return; 99a7210020SGeorge Liu } 100a7210020SGeorge Liu asyncResp->res.addHeader( 101a7210020SGeorge Liu boost::beast::http::field::link, 102a7210020SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby"); 103a7210020SGeorge Liu }); 104a7210020SGeorge Liu } 105a7210020SGeorge Liu 106a7210020SGeorge Liu inline void handlePowerSupplyCollectionGet( 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 116*3e42a329SLakshmi Yadlapati constexpr std::array<std::string_view, 2> chasisInterfaces = { 117*3e42a329SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.Board", 118*3e42a329SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.Chassis"}; 119*3e42a329SLakshmi Yadlapati const std::string reqpath = "/xyz/openbmc_project/inventory"; 120*3e42a329SLakshmi Yadlapati 121*3e42a329SLakshmi Yadlapati dbus::utility::getAssociatedSubTreePathsById( 122*3e42a329SLakshmi Yadlapati chassisId, reqpath, chasisInterfaces, "powered_by", 123*3e42a329SLakshmi Yadlapati powerSupplyInterface, 124*3e42a329SLakshmi Yadlapati [asyncResp, chassisId]( 125*3e42a329SLakshmi Yadlapati const boost::system::error_code& ec, 126*3e42a329SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) { 127*3e42a329SLakshmi Yadlapati doPowerSupplyCollection(asyncResp, chassisId, ec, subtreePaths); 128*3e42a329SLakshmi Yadlapati }); 129a7210020SGeorge Liu } 130a7210020SGeorge Liu 131a7210020SGeorge Liu inline void requestRoutesPowerSupplyCollection(App& app) 132a7210020SGeorge Liu { 133a7210020SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/") 134a7210020SGeorge Liu .privileges(redfish::privileges::headPowerSupplyCollection) 135a7210020SGeorge Liu .methods(boost::beast::http::verb::head)( 136a7210020SGeorge Liu std::bind_front(handlePowerSupplyCollectionHead, std::ref(app))); 137a7210020SGeorge Liu 138a7210020SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/") 139a7210020SGeorge Liu .privileges(redfish::privileges::getPowerSupplyCollection) 140a7210020SGeorge Liu .methods(boost::beast::http::verb::get)( 141a7210020SGeorge Liu std::bind_front(handlePowerSupplyCollectionGet, std::ref(app))); 142a7210020SGeorge Liu } 143a7210020SGeorge Liu 144*3e42a329SLakshmi Yadlapati inline void afterGetValidPowerSupplyPath( 14534dfcb94SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 146*3e42a329SLakshmi Yadlapati const std::string& powerSupplyId, const boost::system::error_code& ec, 147*3e42a329SLakshmi Yadlapati const dbus::utility::MapperGetSubTreeResponse& subtree, 148*3e42a329SLakshmi Yadlapati const std::function<void(const std::string& powerSupplyPath, 149*3e42a329SLakshmi Yadlapati const std::string& service)>& callback) 15000ef5dc6SGeorge Liu { 15100ef5dc6SGeorge Liu if (ec) 15200ef5dc6SGeorge Liu { 15300ef5dc6SGeorge Liu if (ec.value() != EBADR) 15400ef5dc6SGeorge Liu { 155*3e42a329SLakshmi Yadlapati BMCWEB_LOG_ERROR("DBUS response error{}", ec.value()); 15600ef5dc6SGeorge Liu messages::internalError(asyncResp->res); 157*3e42a329SLakshmi Yadlapati } 15800ef5dc6SGeorge Liu return; 15900ef5dc6SGeorge Liu } 160*3e42a329SLakshmi Yadlapati for (const auto& [objectPath, service] : subtree) 16100ef5dc6SGeorge Liu { 162*3e42a329SLakshmi Yadlapati sdbusplus::message::object_path path(objectPath); 163*3e42a329SLakshmi Yadlapati if (path == powerSupplyId) 16400ef5dc6SGeorge Liu { 165*3e42a329SLakshmi Yadlapati callback(path, service.begin()->first); 16600ef5dc6SGeorge Liu return; 16700ef5dc6SGeorge Liu } 16800ef5dc6SGeorge Liu } 16900ef5dc6SGeorge Liu 17062598e31SEd Tanous BMCWEB_LOG_WARNING("Power supply not found: {}", powerSupplyId); 171*3e42a329SLakshmi Yadlapati messages::resourceNotFound(asyncResp->res, "PowerSupplies", powerSupplyId); 17200ef5dc6SGeorge Liu } 173*3e42a329SLakshmi Yadlapati 174*3e42a329SLakshmi Yadlapati inline void getValidPowerSupplyPath( 175*3e42a329SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 176*3e42a329SLakshmi Yadlapati const std::string& chassisId, const std::string& powerSupplyId, 177*3e42a329SLakshmi Yadlapati std::function<void(const std::string& powerSupplyPath, 178*3e42a329SLakshmi Yadlapati const std::string& service)>&& callback) 179*3e42a329SLakshmi Yadlapati { 180*3e42a329SLakshmi Yadlapati constexpr std::array<std::string_view, 2> chasisInterfaces = { 181*3e42a329SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.Board", 182*3e42a329SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.Chassis"}; 183*3e42a329SLakshmi Yadlapati const std::string reqpath = "/xyz/openbmc_project/inventory"; 184*3e42a329SLakshmi Yadlapati 185*3e42a329SLakshmi Yadlapati dbus::utility::getAssociatedSubTreeById( 186*3e42a329SLakshmi Yadlapati chassisId, reqpath, chasisInterfaces, "powered_by", 187*3e42a329SLakshmi Yadlapati powerSupplyInterface, 188*3e42a329SLakshmi Yadlapati [asyncResp, chassisId, powerSupplyId, callback{std::move(callback)}]( 189*3e42a329SLakshmi Yadlapati const boost::system::error_code& ec, 190*3e42a329SLakshmi Yadlapati const dbus::utility::MapperGetSubTreeResponse& subtree) { 191*3e42a329SLakshmi Yadlapati afterGetValidPowerSupplyPath(asyncResp, powerSupplyId, ec, subtree, 192*3e42a329SLakshmi Yadlapati callback); 19300ef5dc6SGeorge Liu }); 19400ef5dc6SGeorge Liu } 19500ef5dc6SGeorge Liu 19600ef5dc6SGeorge Liu inline void 19734dfcb94SGeorge Liu getPowerSupplyState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 19834dfcb94SGeorge Liu const std::string& service, const std::string& path) 19934dfcb94SGeorge Liu { 20034dfcb94SGeorge Liu sdbusplus::asio::getProperty<bool>( 20134dfcb94SGeorge Liu *crow::connections::systemBus, service, path, 20234dfcb94SGeorge Liu "xyz.openbmc_project.Inventory.Item", "Present", 20334dfcb94SGeorge Liu [asyncResp](const boost::system::error_code& ec, const bool value) { 20434dfcb94SGeorge Liu if (ec) 20534dfcb94SGeorge Liu { 20634dfcb94SGeorge Liu if (ec.value() != EBADR) 20734dfcb94SGeorge Liu { 20862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for State {}", 20962598e31SEd Tanous ec.value()); 21034dfcb94SGeorge Liu messages::internalError(asyncResp->res); 21134dfcb94SGeorge Liu } 21234dfcb94SGeorge Liu return; 21334dfcb94SGeorge Liu } 21434dfcb94SGeorge Liu 21534dfcb94SGeorge Liu if (!value) 21634dfcb94SGeorge Liu { 217539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 218539d8c6bSEd Tanous resource::State::Absent; 21934dfcb94SGeorge Liu } 22034dfcb94SGeorge Liu }); 22134dfcb94SGeorge Liu } 22234dfcb94SGeorge Liu 22334dfcb94SGeorge Liu inline void 22434dfcb94SGeorge Liu getPowerSupplyHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 22534dfcb94SGeorge Liu const std::string& service, const std::string& path) 22634dfcb94SGeorge Liu { 22734dfcb94SGeorge Liu sdbusplus::asio::getProperty<bool>( 22834dfcb94SGeorge Liu *crow::connections::systemBus, service, path, 22934dfcb94SGeorge Liu "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 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 Health {}", 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"]["Health"] = 245539d8c6bSEd Tanous resource::Health::Critical; 24634dfcb94SGeorge Liu } 24734dfcb94SGeorge Liu }); 24834dfcb94SGeorge Liu } 24934dfcb94SGeorge Liu 25034dfcb94SGeorge Liu inline void 2512b45fb3bSGeorge Liu getPowerSupplyAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2522b45fb3bSGeorge Liu const std::string& service, const std::string& path) 2532b45fb3bSGeorge Liu { 2542b45fb3bSGeorge Liu sdbusplus::asio::getAllProperties( 2552b45fb3bSGeorge Liu *crow::connections::systemBus, service, path, 2562b45fb3bSGeorge Liu "xyz.openbmc_project.Inventory.Decorator.Asset", 2572b45fb3bSGeorge Liu [asyncResp](const boost::system::error_code& ec, 2582b45fb3bSGeorge Liu const dbus::utility::DBusPropertiesMap& propertiesList) { 2592b45fb3bSGeorge Liu if (ec) 2602b45fb3bSGeorge Liu { 2612b45fb3bSGeorge Liu if (ec.value() != EBADR) 2622b45fb3bSGeorge Liu { 26362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Asset {}", 26462598e31SEd Tanous ec.value()); 2652b45fb3bSGeorge Liu messages::internalError(asyncResp->res); 2662b45fb3bSGeorge Liu } 2672b45fb3bSGeorge Liu return; 2682b45fb3bSGeorge Liu } 2692b45fb3bSGeorge Liu 2702b45fb3bSGeorge Liu const std::string* partNumber = nullptr; 2712b45fb3bSGeorge Liu const std::string* serialNumber = nullptr; 2722b45fb3bSGeorge Liu const std::string* manufacturer = nullptr; 2732b45fb3bSGeorge Liu const std::string* model = nullptr; 2742b45fb3bSGeorge Liu const std::string* sparePartNumber = nullptr; 2752b45fb3bSGeorge Liu 2762b45fb3bSGeorge Liu const bool success = sdbusplus::unpackPropertiesNoThrow( 2772b45fb3bSGeorge Liu dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 2782b45fb3bSGeorge Liu partNumber, "SerialNumber", serialNumber, "Manufacturer", 279bd79bce8SPatrick Williams manufacturer, "Model", model, "SparePartNumber", 280bd79bce8SPatrick Williams sparePartNumber); 2812b45fb3bSGeorge Liu 2822b45fb3bSGeorge Liu if (!success) 2832b45fb3bSGeorge Liu { 2842b45fb3bSGeorge Liu messages::internalError(asyncResp->res); 2852b45fb3bSGeorge Liu return; 2862b45fb3bSGeorge Liu } 2872b45fb3bSGeorge Liu 2882b45fb3bSGeorge Liu if (partNumber != nullptr) 2892b45fb3bSGeorge Liu { 2902b45fb3bSGeorge Liu asyncResp->res.jsonValue["PartNumber"] = *partNumber; 2912b45fb3bSGeorge Liu } 2922b45fb3bSGeorge Liu 2932b45fb3bSGeorge Liu if (serialNumber != nullptr) 2942b45fb3bSGeorge Liu { 2952b45fb3bSGeorge Liu asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 2962b45fb3bSGeorge Liu } 2972b45fb3bSGeorge Liu 2982b45fb3bSGeorge Liu if (manufacturer != nullptr) 2992b45fb3bSGeorge Liu { 3002b45fb3bSGeorge Liu asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 3012b45fb3bSGeorge Liu } 3022b45fb3bSGeorge Liu 3032b45fb3bSGeorge Liu if (model != nullptr) 3042b45fb3bSGeorge Liu { 3052b45fb3bSGeorge Liu asyncResp->res.jsonValue["Model"] = *model; 3062b45fb3bSGeorge Liu } 3072b45fb3bSGeorge Liu 3082b45fb3bSGeorge Liu // SparePartNumber is optional on D-Bus so skip if it is empty 3092b45fb3bSGeorge Liu if (sparePartNumber != nullptr && !sparePartNumber->empty()) 3102b45fb3bSGeorge Liu { 3112b45fb3bSGeorge Liu asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 3122b45fb3bSGeorge Liu } 3132b45fb3bSGeorge Liu }); 3142b45fb3bSGeorge Liu } 3152b45fb3bSGeorge Liu 316a0dba87bSGeorge Liu inline void getPowerSupplyFirmwareVersion( 317a0dba87bSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 318a0dba87bSGeorge Liu const std::string& service, const std::string& path) 319a0dba87bSGeorge Liu { 320a0dba87bSGeorge Liu sdbusplus::asio::getProperty<std::string>( 321a0dba87bSGeorge Liu *crow::connections::systemBus, service, path, 322a0dba87bSGeorge Liu "xyz.openbmc_project.Software.Version", "Version", 323a0dba87bSGeorge Liu [asyncResp](const boost::system::error_code& ec, 324a0dba87bSGeorge Liu const std::string& value) { 325a0dba87bSGeorge Liu if (ec) 326a0dba87bSGeorge Liu { 327a0dba87bSGeorge Liu if (ec.value() != EBADR) 328a0dba87bSGeorge Liu { 329bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 330bd79bce8SPatrick Williams "DBUS response error for FirmwareVersion {}", 33162598e31SEd Tanous ec.value()); 332a0dba87bSGeorge Liu messages::internalError(asyncResp->res); 333a0dba87bSGeorge Liu } 334a0dba87bSGeorge Liu return; 335a0dba87bSGeorge Liu } 336a0dba87bSGeorge Liu asyncResp->res.jsonValue["FirmwareVersion"] = value; 337a0dba87bSGeorge Liu }); 338a0dba87bSGeorge Liu } 339a0dba87bSGeorge Liu 3402b45fb3bSGeorge Liu inline void 34144845e5fSGeorge Liu getPowerSupplyLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 34244845e5fSGeorge Liu const std::string& service, const std::string& path) 34344845e5fSGeorge Liu { 34444845e5fSGeorge Liu sdbusplus::asio::getProperty<std::string>( 34544845e5fSGeorge Liu *crow::connections::systemBus, service, path, 34644845e5fSGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 34744845e5fSGeorge Liu [asyncResp](const boost::system::error_code& ec, 34844845e5fSGeorge Liu const std::string& value) { 34944845e5fSGeorge Liu if (ec) 35044845e5fSGeorge Liu { 35144845e5fSGeorge Liu if (ec.value() != EBADR) 35244845e5fSGeorge Liu { 35362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Location {}", 35462598e31SEd Tanous ec.value()); 35544845e5fSGeorge Liu messages::internalError(asyncResp->res); 35644845e5fSGeorge Liu } 35744845e5fSGeorge Liu return; 35844845e5fSGeorge Liu } 359bd79bce8SPatrick Williams asyncResp->res 360bd79bce8SPatrick Williams .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = value; 36144845e5fSGeorge Liu }); 36244845e5fSGeorge Liu } 36344845e5fSGeorge Liu 364ddceee07SGeorge Liu inline void handleGetEfficiencyResponse( 365ddceee07SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 366ddceee07SGeorge Liu const boost::system::error_code& ec, uint32_t value) 367ddceee07SGeorge Liu { 368ddceee07SGeorge Liu if (ec) 369ddceee07SGeorge Liu { 370ddceee07SGeorge Liu if (ec.value() != EBADR) 371ddceee07SGeorge Liu { 37262598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for DeratingFactor {}", 37362598e31SEd Tanous ec.value()); 374ddceee07SGeorge Liu messages::internalError(asyncResp->res); 375ddceee07SGeorge Liu } 376ddceee07SGeorge Liu return; 377ddceee07SGeorge Liu } 378ddceee07SGeorge Liu // The PDI default value is 0, if it hasn't been set leave off 379ddceee07SGeorge Liu if (value == 0) 380ddceee07SGeorge Liu { 381ddceee07SGeorge Liu return; 382ddceee07SGeorge Liu } 383ddceee07SGeorge Liu 384ddceee07SGeorge Liu nlohmann::json::array_t efficiencyRatings; 385ddceee07SGeorge Liu nlohmann::json::object_t efficiencyPercent; 386ddceee07SGeorge Liu efficiencyPercent["EfficiencyPercent"] = value; 387ddceee07SGeorge Liu efficiencyRatings.emplace_back(std::move(efficiencyPercent)); 388ddceee07SGeorge Liu asyncResp->res.jsonValue["EfficiencyRatings"] = 389ddceee07SGeorge Liu std::move(efficiencyRatings); 390ddceee07SGeorge Liu } 391ddceee07SGeorge Liu 392ddceee07SGeorge Liu inline void handlePowerSupplyAttributesSubTreeResponse( 393ddceee07SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 394ddceee07SGeorge Liu const boost::system::error_code& ec, 395ddceee07SGeorge Liu const dbus::utility::MapperGetSubTreeResponse& subtree) 396ddceee07SGeorge Liu { 397ddceee07SGeorge Liu if (ec) 398ddceee07SGeorge Liu { 399ddceee07SGeorge Liu if (ec.value() != EBADR) 400ddceee07SGeorge Liu { 40162598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for EfficiencyPercent {}", 40262598e31SEd Tanous ec.value()); 403ddceee07SGeorge Liu messages::internalError(asyncResp->res); 404ddceee07SGeorge Liu } 405ddceee07SGeorge Liu return; 406ddceee07SGeorge Liu } 407ddceee07SGeorge Liu 408ddceee07SGeorge Liu if (subtree.empty()) 409ddceee07SGeorge Liu { 41062598e31SEd Tanous BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!"); 411ddceee07SGeorge Liu return; 412ddceee07SGeorge Liu } 413ddceee07SGeorge Liu 414ddceee07SGeorge Liu if (subtree.size() != 1) 415ddceee07SGeorge Liu { 41662598e31SEd Tanous BMCWEB_LOG_ERROR( 41762598e31SEd Tanous "Unexpected number of paths returned by getSubTree: {}", 41862598e31SEd Tanous subtree.size()); 419ddceee07SGeorge Liu messages::internalError(asyncResp->res); 420ddceee07SGeorge Liu return; 421ddceee07SGeorge Liu } 422ddceee07SGeorge Liu 423ddceee07SGeorge Liu const auto& [path, serviceMap] = *subtree.begin(); 424ddceee07SGeorge Liu const auto& [service, interfaces] = *serviceMap.begin(); 425ddceee07SGeorge Liu sdbusplus::asio::getProperty<uint32_t>( 426ddceee07SGeorge Liu *crow::connections::systemBus, service, path, 427ddceee07SGeorge Liu "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor", 428ddceee07SGeorge Liu [asyncResp](const boost::system::error_code& ec1, uint32_t value) { 429ddceee07SGeorge Liu handleGetEfficiencyResponse(asyncResp, ec1, value); 430ddceee07SGeorge Liu }); 431ddceee07SGeorge Liu } 432ddceee07SGeorge Liu 433ddceee07SGeorge Liu inline void 434ddceee07SGeorge Liu getEfficiencyPercent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 435ddceee07SGeorge Liu { 436ddceee07SGeorge Liu constexpr std::array<std::string_view, 1> efficiencyIntf = { 437ddceee07SGeorge Liu "xyz.openbmc_project.Control.PowerSupplyAttributes"}; 438ddceee07SGeorge Liu 439ddceee07SGeorge Liu dbus::utility::getSubTree( 440ddceee07SGeorge Liu "/xyz/openbmc_project", 0, efficiencyIntf, 441ddceee07SGeorge Liu [asyncResp](const boost::system::error_code& ec, 442ddceee07SGeorge Liu const dbus::utility::MapperGetSubTreeResponse& subtree) { 443ddceee07SGeorge Liu handlePowerSupplyAttributesSubTreeResponse(asyncResp, ec, subtree); 444ddceee07SGeorge Liu }); 445ddceee07SGeorge Liu } 446ddceee07SGeorge Liu 447bd79bce8SPatrick Williams inline void doPowerSupplyGet( 448bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 449bd79bce8SPatrick Williams const std::string& chassisId, const std::string& powerSupplyId, 450*3e42a329SLakshmi Yadlapati const std::string& powerSupplyPath, const std::string& service) 45100ef5dc6SGeorge Liu { 45200ef5dc6SGeorge Liu asyncResp->res.addHeader( 45300ef5dc6SGeorge Liu boost::beast::http::field::link, 45400ef5dc6SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby"); 455*3e42a329SLakshmi Yadlapati asyncResp->res.jsonValue["@odata.type"] = "#PowerSupply.v1_5_0.PowerSupply"; 45600ef5dc6SGeorge Liu asyncResp->res.jsonValue["Name"] = "Power Supply"; 45700ef5dc6SGeorge Liu asyncResp->res.jsonValue["Id"] = powerSupplyId; 45800ef5dc6SGeorge Liu asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 459*3e42a329SLakshmi Yadlapati "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId, 460*3e42a329SLakshmi Yadlapati powerSupplyId); 46134dfcb94SGeorge Liu 462*3e42a329SLakshmi Yadlapati asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 463539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK; 46434dfcb94SGeorge Liu 465*3e42a329SLakshmi Yadlapati getPowerSupplyState(asyncResp, service, powerSupplyPath); 466*3e42a329SLakshmi Yadlapati getPowerSupplyHealth(asyncResp, service, powerSupplyPath); 467*3e42a329SLakshmi Yadlapati getPowerSupplyAsset(asyncResp, service, powerSupplyPath); 468*3e42a329SLakshmi Yadlapati getPowerSupplyFirmwareVersion(asyncResp, service, powerSupplyPath); 469*3e42a329SLakshmi Yadlapati getPowerSupplyLocation(asyncResp, service, powerSupplyPath); 470ddceee07SGeorge Liu getEfficiencyPercent(asyncResp); 47100ef5dc6SGeorge Liu } 47200ef5dc6SGeorge Liu 473bd79bce8SPatrick Williams inline void handlePowerSupplyHead( 474bd79bce8SPatrick Williams App& app, const crow::Request& req, 47500ef5dc6SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 476bd79bce8SPatrick Williams const std::string& chassisId, const std::string& powerSupplyId) 47700ef5dc6SGeorge Liu { 47800ef5dc6SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 47900ef5dc6SGeorge Liu { 48000ef5dc6SGeorge Liu return; 48100ef5dc6SGeorge Liu } 48200ef5dc6SGeorge Liu 48300ef5dc6SGeorge Liu // Get the correct Path and Service that match the input parameters 484bd79bce8SPatrick Williams getValidPowerSupplyPath( 485*3e42a329SLakshmi Yadlapati asyncResp, chassisId, powerSupplyId, 486*3e42a329SLakshmi Yadlapati [asyncResp](const std::string&, const std::string&) { 48700ef5dc6SGeorge Liu asyncResp->res.addHeader( 48800ef5dc6SGeorge Liu boost::beast::http::field::link, 48900ef5dc6SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby"); 49000ef5dc6SGeorge Liu }); 49100ef5dc6SGeorge Liu } 49200ef5dc6SGeorge Liu 493bd79bce8SPatrick Williams inline void handlePowerSupplyGet( 494bd79bce8SPatrick Williams App& app, const crow::Request& req, 49500ef5dc6SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 496bd79bce8SPatrick Williams const std::string& chassisId, const std::string& powerSupplyId) 49700ef5dc6SGeorge Liu { 49800ef5dc6SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 49900ef5dc6SGeorge Liu { 50000ef5dc6SGeorge Liu return; 50100ef5dc6SGeorge Liu } 502*3e42a329SLakshmi Yadlapati getValidPowerSupplyPath( 503*3e42a329SLakshmi Yadlapati asyncResp, chassisId, powerSupplyId, 50400ef5dc6SGeorge Liu std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId)); 50500ef5dc6SGeorge Liu } 50600ef5dc6SGeorge Liu 50700ef5dc6SGeorge Liu inline void requestRoutesPowerSupply(App& app) 50800ef5dc6SGeorge Liu { 50900ef5dc6SGeorge Liu BMCWEB_ROUTE( 51000ef5dc6SGeorge Liu app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/") 51100ef5dc6SGeorge Liu .privileges(redfish::privileges::headPowerSupply) 51200ef5dc6SGeorge Liu .methods(boost::beast::http::verb::head)( 51300ef5dc6SGeorge Liu std::bind_front(handlePowerSupplyHead, std::ref(app))); 51400ef5dc6SGeorge Liu 51500ef5dc6SGeorge Liu BMCWEB_ROUTE( 51600ef5dc6SGeorge Liu app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/") 51700ef5dc6SGeorge Liu .privileges(redfish::privileges::getPowerSupply) 51800ef5dc6SGeorge Liu .methods(boost::beast::http::verb::get)( 51900ef5dc6SGeorge Liu std::bind_front(handlePowerSupplyGet, std::ref(app))); 52000ef5dc6SGeorge Liu } 52100ef5dc6SGeorge Liu 522a7210020SGeorge Liu } // namespace redfish 523