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