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" 11d7857201SEd Tanous #include "logging.hpp" 12a7210020SGeorge Liu #include "query.hpp" 13a7210020SGeorge Liu #include "registries/privilege_registry.hpp" 14a7210020SGeorge Liu #include "utils/chassis_utils.hpp" 152b45fb3bSGeorge Liu #include "utils/dbus_utils.hpp" 16b5190062SHieu Huynh #include "utils/time_utils.hpp" 17a7210020SGeorge Liu 18d7857201SEd Tanous #include <asm-generic/errno.h> 19d7857201SEd Tanous 20d7857201SEd Tanous #include <boost/beast/http/field.hpp> 21d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 2234dfcb94SGeorge Liu #include <boost/system/error_code.hpp> 23ef4c65b7SEd Tanous #include <boost/url/format.hpp> 24d7857201SEd Tanous #include <nlohmann/json.hpp> 25d7857201SEd Tanous #include <sdbusplus/unpack_properties.hpp> 26ef4c65b7SEd Tanous 27d7857201SEd Tanous #include <array> 28d7857201SEd Tanous #include <cstdint> 29d7857201SEd Tanous #include <functional> 30a7210020SGeorge Liu #include <memory> 31a7210020SGeorge Liu #include <optional> 32a7210020SGeorge Liu #include <string> 33d7857201SEd Tanous #include <string_view> 34d7857201SEd Tanous #include <utility> 35a7210020SGeorge Liu 36a7210020SGeorge Liu namespace redfish 37a7210020SGeorge Liu { 38a7210020SGeorge Liu 39788fe6cfSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> powerSupplyInterface = { 40788fe6cfSLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PowerSupply"}; 41788fe6cfSLakshmi Yadlapati 42788fe6cfSLakshmi Yadlapati inline void updatePowerSupplyList( 43788fe6cfSLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4400ef5dc6SGeorge Liu const std::string& chassisId, 45788fe6cfSLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& powerSupplyPaths) 46788fe6cfSLakshmi Yadlapati { 47788fe6cfSLakshmi Yadlapati nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"]; 48788fe6cfSLakshmi Yadlapati for (const std::string& powerSupplyPath : powerSupplyPaths) 49a7210020SGeorge Liu { 5000ef5dc6SGeorge Liu std::string powerSupplyName = 5100ef5dc6SGeorge Liu sdbusplus::message::object_path(powerSupplyPath).filename(); 5200ef5dc6SGeorge Liu if (powerSupplyName.empty()) 5300ef5dc6SGeorge Liu { 54788fe6cfSLakshmi Yadlapati continue; 5500ef5dc6SGeorge Liu } 5600ef5dc6SGeorge Liu 5700ef5dc6SGeorge Liu nlohmann::json item = nlohmann::json::object(); 5800ef5dc6SGeorge Liu item["@odata.id"] = boost::urls::format( 5900ef5dc6SGeorge Liu "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId, 6000ef5dc6SGeorge Liu powerSupplyName); 6100ef5dc6SGeorge Liu 6200ef5dc6SGeorge Liu powerSupplyList.emplace_back(std::move(item)); 63788fe6cfSLakshmi Yadlapati } 6400ef5dc6SGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size(); 65a7210020SGeorge Liu } 66a7210020SGeorge Liu 673e42a329SLakshmi Yadlapati inline void doPowerSupplyCollection( 683e42a329SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 693e42a329SLakshmi Yadlapati const std::string& chassisId, const boost::system::error_code& ec, 703e42a329SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) 71a7210020SGeorge Liu { 723e42a329SLakshmi Yadlapati if (ec) 73a7210020SGeorge Liu { 74*193582b6SMyung Bae if (ec.value() == boost::system::errc::io_error) 75*193582b6SMyung Bae { 76*193582b6SMyung Bae BMCWEB_LOG_WARNING("Chassis not found"); 77*193582b6SMyung Bae messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 78*193582b6SMyung Bae return; 79*193582b6SMyung Bae } 803e42a329SLakshmi Yadlapati if (ec.value() != EBADR) 813e42a329SLakshmi Yadlapati { 823e42a329SLakshmi Yadlapati BMCWEB_LOG_ERROR("DBUS response error{}", ec.value()); 833e42a329SLakshmi Yadlapati messages::internalError(asyncResp->res); 843e42a329SLakshmi Yadlapati } 85a7210020SGeorge Liu return; 86a7210020SGeorge Liu } 87a7210020SGeorge Liu asyncResp->res.addHeader( 88a7210020SGeorge Liu boost::beast::http::field::link, 89a7210020SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby"); 90a7210020SGeorge Liu asyncResp->res.jsonValue["@odata.type"] = 91a7210020SGeorge Liu "#PowerSupplyCollection.PowerSupplyCollection"; 92a7210020SGeorge Liu asyncResp->res.jsonValue["Name"] = "Power Supply Collection"; 93ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 94ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId); 95a7210020SGeorge Liu asyncResp->res.jsonValue["Description"] = 96a7210020SGeorge Liu "The collection of PowerSupply resource instances."; 977a2bb2c9SGeorge Liu asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 987a2bb2c9SGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = 0; 99a7210020SGeorge Liu 100788fe6cfSLakshmi Yadlapati updatePowerSupplyList(asyncResp, chassisId, subtreePaths); 101a7210020SGeorge Liu } 102a7210020SGeorge Liu 103a7210020SGeorge Liu inline void handlePowerSupplyCollectionHead( 104a7210020SGeorge Liu App& app, const crow::Request& req, 105a7210020SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 106a7210020SGeorge Liu const std::string& chassisId) 107a7210020SGeorge Liu { 108a7210020SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 109a7210020SGeorge Liu { 110a7210020SGeorge Liu return; 111a7210020SGeorge Liu } 112a7210020SGeorge Liu 113a7210020SGeorge Liu redfish::chassis_utils::getValidChassisPath( 114a7210020SGeorge Liu asyncResp, chassisId, 115a7210020SGeorge Liu [asyncResp, 116a7210020SGeorge Liu chassisId](const std::optional<std::string>& validChassisPath) { 117a7210020SGeorge Liu if (!validChassisPath) 118a7210020SGeorge Liu { 119*193582b6SMyung Bae BMCWEB_LOG_WARNING("Chassis not found"); 120bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Chassis", 121bd79bce8SPatrick Williams chassisId); 122a7210020SGeorge Liu return; 123a7210020SGeorge Liu } 124a7210020SGeorge Liu asyncResp->res.addHeader( 125a7210020SGeorge Liu boost::beast::http::field::link, 126a7210020SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby"); 127a7210020SGeorge Liu }); 128a7210020SGeorge Liu } 129a7210020SGeorge Liu 130a7210020SGeorge Liu inline void handlePowerSupplyCollectionGet( 131a7210020SGeorge Liu App& app, const crow::Request& req, 132a7210020SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 133a7210020SGeorge Liu const std::string& chassisId) 134a7210020SGeorge Liu { 135a7210020SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 136a7210020SGeorge Liu { 137a7210020SGeorge Liu return; 138a7210020SGeorge Liu } 139a7210020SGeorge Liu 1403e42a329SLakshmi Yadlapati const std::string reqpath = "/xyz/openbmc_project/inventory"; 1413e42a329SLakshmi Yadlapati 1423e42a329SLakshmi Yadlapati dbus::utility::getAssociatedSubTreePathsById( 1433f95a277SMyung Bae chassisId, reqpath, chassisInterfaces, "powered_by", 1443e42a329SLakshmi Yadlapati powerSupplyInterface, 1453e42a329SLakshmi Yadlapati [asyncResp, chassisId]( 1463e42a329SLakshmi Yadlapati const boost::system::error_code& ec, 1473e42a329SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) { 1483e42a329SLakshmi Yadlapati doPowerSupplyCollection(asyncResp, chassisId, ec, subtreePaths); 1493e42a329SLakshmi Yadlapati }); 150a7210020SGeorge Liu } 151a7210020SGeorge Liu 152a7210020SGeorge Liu inline void requestRoutesPowerSupplyCollection(App& app) 153a7210020SGeorge Liu { 154a7210020SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/") 155a7210020SGeorge Liu .privileges(redfish::privileges::headPowerSupplyCollection) 156a7210020SGeorge Liu .methods(boost::beast::http::verb::head)( 157a7210020SGeorge Liu std::bind_front(handlePowerSupplyCollectionHead, std::ref(app))); 158a7210020SGeorge Liu 159a7210020SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/") 160a7210020SGeorge Liu .privileges(redfish::privileges::getPowerSupplyCollection) 161a7210020SGeorge Liu .methods(boost::beast::http::verb::get)( 162a7210020SGeorge Liu std::bind_front(handlePowerSupplyCollectionGet, std::ref(app))); 163a7210020SGeorge Liu } 164a7210020SGeorge Liu 1653e42a329SLakshmi Yadlapati inline void afterGetValidPowerSupplyPath( 16634dfcb94SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1673e42a329SLakshmi Yadlapati const std::string& powerSupplyId, const boost::system::error_code& ec, 1683e42a329SLakshmi Yadlapati const dbus::utility::MapperGetSubTreeResponse& subtree, 1693e42a329SLakshmi Yadlapati const std::function<void(const std::string& powerSupplyPath, 1703e42a329SLakshmi Yadlapati const std::string& service)>& callback) 17100ef5dc6SGeorge Liu { 17200ef5dc6SGeorge Liu if (ec) 17300ef5dc6SGeorge Liu { 174*193582b6SMyung Bae if (ec.value() == boost::system::errc::io_error) 175*193582b6SMyung Bae { 176*193582b6SMyung Bae // Not found 177*193582b6SMyung Bae callback(std::string(), std::string()); 178*193582b6SMyung Bae return; 179*193582b6SMyung Bae } 18000ef5dc6SGeorge Liu if (ec.value() != EBADR) 18100ef5dc6SGeorge Liu { 1823e42a329SLakshmi Yadlapati BMCWEB_LOG_ERROR("DBUS response error{}", ec.value()); 18300ef5dc6SGeorge Liu messages::internalError(asyncResp->res); 184*193582b6SMyung Bae return; 1853e42a329SLakshmi Yadlapati } 186*193582b6SMyung Bae callback(std::string(), std::string()); 18700ef5dc6SGeorge Liu return; 18800ef5dc6SGeorge Liu } 1893e42a329SLakshmi Yadlapati for (const auto& [objectPath, service] : subtree) 19000ef5dc6SGeorge Liu { 1913e42a329SLakshmi Yadlapati sdbusplus::message::object_path path(objectPath); 192d8e2b618SMyung Bae if (path.filename() == powerSupplyId) 19300ef5dc6SGeorge Liu { 1943e42a329SLakshmi Yadlapati callback(path, service.begin()->first); 19500ef5dc6SGeorge Liu return; 19600ef5dc6SGeorge Liu } 19700ef5dc6SGeorge Liu } 19800ef5dc6SGeorge Liu 19962598e31SEd Tanous BMCWEB_LOG_WARNING("Power supply not found: {}", powerSupplyId); 2003e42a329SLakshmi Yadlapati messages::resourceNotFound(asyncResp->res, "PowerSupplies", powerSupplyId); 20100ef5dc6SGeorge Liu } 2023e42a329SLakshmi Yadlapati 2033e42a329SLakshmi Yadlapati inline void getValidPowerSupplyPath( 2043e42a329SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2053e42a329SLakshmi Yadlapati const std::string& chassisId, const std::string& powerSupplyId, 2063e42a329SLakshmi Yadlapati std::function<void(const std::string& powerSupplyPath, 2073e42a329SLakshmi Yadlapati const std::string& service)>&& callback) 2083e42a329SLakshmi Yadlapati { 2093e42a329SLakshmi Yadlapati const std::string reqpath = "/xyz/openbmc_project/inventory"; 2103e42a329SLakshmi Yadlapati 2113e42a329SLakshmi Yadlapati dbus::utility::getAssociatedSubTreeById( 2123f95a277SMyung Bae chassisId, reqpath, chassisInterfaces, "powered_by", 2133e42a329SLakshmi Yadlapati powerSupplyInterface, 2143e42a329SLakshmi Yadlapati [asyncResp, chassisId, powerSupplyId, callback{std::move(callback)}]( 2153e42a329SLakshmi Yadlapati const boost::system::error_code& ec, 2163e42a329SLakshmi Yadlapati const dbus::utility::MapperGetSubTreeResponse& subtree) { 2173e42a329SLakshmi Yadlapati afterGetValidPowerSupplyPath(asyncResp, powerSupplyId, ec, subtree, 2183e42a329SLakshmi Yadlapati callback); 21900ef5dc6SGeorge Liu }); 22000ef5dc6SGeorge Liu } 22100ef5dc6SGeorge Liu 222504af5a0SPatrick Williams inline void getPowerSupplyState( 223504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 22434dfcb94SGeorge Liu const std::string& service, const std::string& path) 22534dfcb94SGeorge Liu { 226deae6a78SEd Tanous dbus::utility::getProperty<bool>( 227deae6a78SEd Tanous service, path, "xyz.openbmc_project.Inventory.Item", "Present", 22834dfcb94SGeorge Liu [asyncResp](const boost::system::error_code& ec, const bool value) { 22934dfcb94SGeorge Liu if (ec) 23034dfcb94SGeorge Liu { 23134dfcb94SGeorge Liu if (ec.value() != EBADR) 23234dfcb94SGeorge Liu { 23362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for State {}", 23462598e31SEd Tanous ec.value()); 23534dfcb94SGeorge Liu messages::internalError(asyncResp->res); 23634dfcb94SGeorge Liu } 23734dfcb94SGeorge Liu return; 23834dfcb94SGeorge Liu } 23934dfcb94SGeorge Liu 24034dfcb94SGeorge Liu if (!value) 24134dfcb94SGeorge Liu { 242539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 243539d8c6bSEd Tanous resource::State::Absent; 24434dfcb94SGeorge Liu } 24534dfcb94SGeorge Liu }); 24634dfcb94SGeorge Liu } 24734dfcb94SGeorge Liu 248504af5a0SPatrick Williams inline void getPowerSupplyHealth( 249504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 25034dfcb94SGeorge Liu const std::string& service, const std::string& path) 25134dfcb94SGeorge Liu { 252deae6a78SEd Tanous dbus::utility::getProperty<bool>( 253deae6a78SEd Tanous service, path, "xyz.openbmc_project.State.Decorator.OperationalStatus", 254deae6a78SEd Tanous "Functional", 25534dfcb94SGeorge Liu [asyncResp](const boost::system::error_code& ec, const bool value) { 25634dfcb94SGeorge Liu if (ec) 25734dfcb94SGeorge Liu { 25834dfcb94SGeorge Liu if (ec.value() != EBADR) 25934dfcb94SGeorge Liu { 26062598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Health {}", 26162598e31SEd Tanous ec.value()); 26234dfcb94SGeorge Liu messages::internalError(asyncResp->res); 26334dfcb94SGeorge Liu } 26434dfcb94SGeorge Liu return; 26534dfcb94SGeorge Liu } 26634dfcb94SGeorge Liu 26734dfcb94SGeorge Liu if (!value) 26834dfcb94SGeorge Liu { 269539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = 270539d8c6bSEd Tanous resource::Health::Critical; 27134dfcb94SGeorge Liu } 27234dfcb94SGeorge Liu }); 27334dfcb94SGeorge Liu } 27434dfcb94SGeorge Liu 275504af5a0SPatrick Williams inline void getPowerSupplyAsset( 276504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2772b45fb3bSGeorge Liu const std::string& service, const std::string& path) 2782b45fb3bSGeorge Liu { 279deae6a78SEd Tanous dbus::utility::getAllProperties( 280deae6a78SEd Tanous service, path, "xyz.openbmc_project.Inventory.Decorator.Asset", 2812b45fb3bSGeorge Liu [asyncResp](const boost::system::error_code& ec, 2822b45fb3bSGeorge Liu const dbus::utility::DBusPropertiesMap& propertiesList) { 2832b45fb3bSGeorge Liu if (ec) 2842b45fb3bSGeorge Liu { 2852b45fb3bSGeorge Liu if (ec.value() != EBADR) 2862b45fb3bSGeorge Liu { 28762598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Asset {}", 28862598e31SEd Tanous ec.value()); 2892b45fb3bSGeorge Liu messages::internalError(asyncResp->res); 2902b45fb3bSGeorge Liu } 2912b45fb3bSGeorge Liu return; 2922b45fb3bSGeorge Liu } 2932b45fb3bSGeorge Liu 2942b45fb3bSGeorge Liu const std::string* partNumber = nullptr; 2952b45fb3bSGeorge Liu const std::string* serialNumber = nullptr; 2962b45fb3bSGeorge Liu const std::string* manufacturer = nullptr; 2972b45fb3bSGeorge Liu const std::string* model = nullptr; 2982b45fb3bSGeorge Liu const std::string* sparePartNumber = nullptr; 299b5190062SHieu Huynh const std::string* buildDate = nullptr; 3002b45fb3bSGeorge Liu 3012b45fb3bSGeorge Liu const bool success = sdbusplus::unpackPropertiesNoThrow( 3022b45fb3bSGeorge Liu dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 3032b45fb3bSGeorge Liu partNumber, "SerialNumber", serialNumber, "Manufacturer", 304bd79bce8SPatrick Williams manufacturer, "Model", model, "SparePartNumber", 305b5190062SHieu Huynh sparePartNumber, "BuildDate", buildDate); 3062b45fb3bSGeorge Liu 3072b45fb3bSGeorge Liu if (!success) 3082b45fb3bSGeorge Liu { 3092b45fb3bSGeorge Liu messages::internalError(asyncResp->res); 3102b45fb3bSGeorge Liu return; 3112b45fb3bSGeorge Liu } 3122b45fb3bSGeorge Liu 3132b45fb3bSGeorge Liu if (partNumber != nullptr) 3142b45fb3bSGeorge Liu { 3152b45fb3bSGeorge Liu asyncResp->res.jsonValue["PartNumber"] = *partNumber; 3162b45fb3bSGeorge Liu } 3172b45fb3bSGeorge Liu 3182b45fb3bSGeorge Liu if (serialNumber != nullptr) 3192b45fb3bSGeorge Liu { 3202b45fb3bSGeorge Liu asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 3212b45fb3bSGeorge Liu } 3222b45fb3bSGeorge Liu 3232b45fb3bSGeorge Liu if (manufacturer != nullptr) 3242b45fb3bSGeorge Liu { 3252b45fb3bSGeorge Liu asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 3262b45fb3bSGeorge Liu } 3272b45fb3bSGeorge Liu 3282b45fb3bSGeorge Liu if (model != nullptr) 3292b45fb3bSGeorge Liu { 3302b45fb3bSGeorge Liu asyncResp->res.jsonValue["Model"] = *model; 3312b45fb3bSGeorge Liu } 3322b45fb3bSGeorge Liu 3332b45fb3bSGeorge Liu // SparePartNumber is optional on D-Bus so skip if it is empty 3342b45fb3bSGeorge Liu if (sparePartNumber != nullptr && !sparePartNumber->empty()) 3352b45fb3bSGeorge Liu { 3362b45fb3bSGeorge Liu asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 3372b45fb3bSGeorge Liu } 338b5190062SHieu Huynh 339b5190062SHieu Huynh if (buildDate != nullptr) 340b5190062SHieu Huynh { 341b5190062SHieu Huynh time_utils::productionDateReport(asyncResp->res, *buildDate); 342b5190062SHieu Huynh } 3432b45fb3bSGeorge Liu }); 3442b45fb3bSGeorge Liu } 3452b45fb3bSGeorge Liu 346a0dba87bSGeorge Liu inline void getPowerSupplyFirmwareVersion( 347a0dba87bSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 348a0dba87bSGeorge Liu const std::string& service, const std::string& path) 349a0dba87bSGeorge Liu { 350deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 351deae6a78SEd Tanous service, path, "xyz.openbmc_project.Software.Version", "Version", 352a0dba87bSGeorge Liu [asyncResp](const boost::system::error_code& ec, 353a0dba87bSGeorge Liu const std::string& value) { 354a0dba87bSGeorge Liu if (ec) 355a0dba87bSGeorge Liu { 356a0dba87bSGeorge Liu if (ec.value() != EBADR) 357a0dba87bSGeorge Liu { 358bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 359bd79bce8SPatrick Williams "DBUS response error for FirmwareVersion {}", 36062598e31SEd Tanous ec.value()); 361a0dba87bSGeorge Liu messages::internalError(asyncResp->res); 362a0dba87bSGeorge Liu } 363a0dba87bSGeorge Liu return; 364a0dba87bSGeorge Liu } 365a0dba87bSGeorge Liu asyncResp->res.jsonValue["FirmwareVersion"] = value; 366a0dba87bSGeorge Liu }); 367a0dba87bSGeorge Liu } 368a0dba87bSGeorge Liu 369504af5a0SPatrick Williams inline void getPowerSupplyLocation( 370504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 37144845e5fSGeorge Liu const std::string& service, const std::string& path) 37244845e5fSGeorge Liu { 373deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 374deae6a78SEd Tanous service, path, "xyz.openbmc_project.Inventory.Decorator.LocationCode", 375deae6a78SEd Tanous "LocationCode", 37644845e5fSGeorge Liu [asyncResp](const boost::system::error_code& ec, 37744845e5fSGeorge Liu const std::string& value) { 37844845e5fSGeorge Liu if (ec) 37944845e5fSGeorge Liu { 38044845e5fSGeorge Liu if (ec.value() != EBADR) 38144845e5fSGeorge Liu { 38262598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Location {}", 38362598e31SEd Tanous ec.value()); 38444845e5fSGeorge Liu messages::internalError(asyncResp->res); 38544845e5fSGeorge Liu } 38644845e5fSGeorge Liu return; 38744845e5fSGeorge Liu } 388bd79bce8SPatrick Williams asyncResp->res 389bd79bce8SPatrick Williams .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = value; 39044845e5fSGeorge Liu }); 39144845e5fSGeorge Liu } 39244845e5fSGeorge Liu 393ddceee07SGeorge Liu inline void handleGetEfficiencyResponse( 394ddceee07SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 395ddceee07SGeorge Liu const boost::system::error_code& ec, uint32_t value) 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 DeratingFactor {}", 40262598e31SEd Tanous ec.value()); 403ddceee07SGeorge Liu messages::internalError(asyncResp->res); 404ddceee07SGeorge Liu } 405ddceee07SGeorge Liu return; 406ddceee07SGeorge Liu } 407ddceee07SGeorge Liu // The PDI default value is 0, if it hasn't been set leave off 408ddceee07SGeorge Liu if (value == 0) 409ddceee07SGeorge Liu { 410ddceee07SGeorge Liu return; 411ddceee07SGeorge Liu } 412ddceee07SGeorge Liu 413ddceee07SGeorge Liu nlohmann::json::array_t efficiencyRatings; 414ddceee07SGeorge Liu nlohmann::json::object_t efficiencyPercent; 415ddceee07SGeorge Liu efficiencyPercent["EfficiencyPercent"] = value; 416ddceee07SGeorge Liu efficiencyRatings.emplace_back(std::move(efficiencyPercent)); 417ddceee07SGeorge Liu asyncResp->res.jsonValue["EfficiencyRatings"] = 418ddceee07SGeorge Liu std::move(efficiencyRatings); 419ddceee07SGeorge Liu } 420ddceee07SGeorge Liu 421ddceee07SGeorge Liu inline void handlePowerSupplyAttributesSubTreeResponse( 422ddceee07SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 423ddceee07SGeorge Liu const boost::system::error_code& ec, 424ddceee07SGeorge Liu const dbus::utility::MapperGetSubTreeResponse& subtree) 425ddceee07SGeorge Liu { 426ddceee07SGeorge Liu if (ec) 427ddceee07SGeorge Liu { 428ddceee07SGeorge Liu if (ec.value() != EBADR) 429ddceee07SGeorge Liu { 43062598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for EfficiencyPercent {}", 43162598e31SEd Tanous ec.value()); 432ddceee07SGeorge Liu messages::internalError(asyncResp->res); 433ddceee07SGeorge Liu } 434ddceee07SGeorge Liu return; 435ddceee07SGeorge Liu } 436ddceee07SGeorge Liu 437ddceee07SGeorge Liu if (subtree.empty()) 438ddceee07SGeorge Liu { 43962598e31SEd Tanous BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!"); 440ddceee07SGeorge Liu return; 441ddceee07SGeorge Liu } 442ddceee07SGeorge Liu 443ddceee07SGeorge Liu if (subtree.size() != 1) 444ddceee07SGeorge Liu { 44562598e31SEd Tanous BMCWEB_LOG_ERROR( 44662598e31SEd Tanous "Unexpected number of paths returned by getSubTree: {}", 44762598e31SEd Tanous subtree.size()); 448ddceee07SGeorge Liu messages::internalError(asyncResp->res); 449ddceee07SGeorge Liu return; 450ddceee07SGeorge Liu } 451ddceee07SGeorge Liu 452ddceee07SGeorge Liu const auto& [path, serviceMap] = *subtree.begin(); 453ddceee07SGeorge Liu const auto& [service, interfaces] = *serviceMap.begin(); 454deae6a78SEd Tanous dbus::utility::getProperty<uint32_t>( 455deae6a78SEd Tanous service, path, "xyz.openbmc_project.Control.PowerSupplyAttributes", 456deae6a78SEd Tanous "DeratingFactor", 457ddceee07SGeorge Liu [asyncResp](const boost::system::error_code& ec1, uint32_t value) { 458ddceee07SGeorge Liu handleGetEfficiencyResponse(asyncResp, ec1, value); 459ddceee07SGeorge Liu }); 460ddceee07SGeorge Liu } 461ddceee07SGeorge Liu 462504af5a0SPatrick Williams inline void getEfficiencyPercent( 463504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 464ddceee07SGeorge Liu { 465ddceee07SGeorge Liu constexpr std::array<std::string_view, 1> efficiencyIntf = { 466ddceee07SGeorge Liu "xyz.openbmc_project.Control.PowerSupplyAttributes"}; 467ddceee07SGeorge Liu 468ddceee07SGeorge Liu dbus::utility::getSubTree( 469ddceee07SGeorge Liu "/xyz/openbmc_project", 0, efficiencyIntf, 470ddceee07SGeorge Liu [asyncResp](const boost::system::error_code& ec, 471ddceee07SGeorge Liu const dbus::utility::MapperGetSubTreeResponse& subtree) { 472ddceee07SGeorge Liu handlePowerSupplyAttributesSubTreeResponse(asyncResp, ec, subtree); 473ddceee07SGeorge Liu }); 474ddceee07SGeorge Liu } 475ddceee07SGeorge Liu 476bd79bce8SPatrick Williams inline void doPowerSupplyGet( 477bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 478bd79bce8SPatrick Williams const std::string& chassisId, const std::string& powerSupplyId, 4793e42a329SLakshmi Yadlapati const std::string& powerSupplyPath, const std::string& service) 48000ef5dc6SGeorge Liu { 481*193582b6SMyung Bae if (powerSupplyPath.empty() || service.empty()) 482*193582b6SMyung Bae { 483*193582b6SMyung Bae BMCWEB_LOG_WARNING("PowerSupply not found"); 484*193582b6SMyung Bae messages::resourceNotFound(asyncResp->res, "PowerSupply", 485*193582b6SMyung Bae powerSupplyId); 486*193582b6SMyung Bae return; 487*193582b6SMyung Bae } 488*193582b6SMyung Bae 48900ef5dc6SGeorge Liu asyncResp->res.addHeader( 49000ef5dc6SGeorge Liu boost::beast::http::field::link, 49100ef5dc6SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby"); 4923e42a329SLakshmi Yadlapati asyncResp->res.jsonValue["@odata.type"] = "#PowerSupply.v1_5_0.PowerSupply"; 49300ef5dc6SGeorge Liu asyncResp->res.jsonValue["Name"] = "Power Supply"; 49400ef5dc6SGeorge Liu asyncResp->res.jsonValue["Id"] = powerSupplyId; 49500ef5dc6SGeorge Liu asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 4963e42a329SLakshmi Yadlapati "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId, 4973e42a329SLakshmi Yadlapati powerSupplyId); 49834dfcb94SGeorge Liu 4993e42a329SLakshmi Yadlapati asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 500539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK; 50134dfcb94SGeorge Liu 5023e42a329SLakshmi Yadlapati getPowerSupplyState(asyncResp, service, powerSupplyPath); 5033e42a329SLakshmi Yadlapati getPowerSupplyHealth(asyncResp, service, powerSupplyPath); 5043e42a329SLakshmi Yadlapati getPowerSupplyAsset(asyncResp, service, powerSupplyPath); 5053e42a329SLakshmi Yadlapati getPowerSupplyFirmwareVersion(asyncResp, service, powerSupplyPath); 5063e42a329SLakshmi Yadlapati getPowerSupplyLocation(asyncResp, service, powerSupplyPath); 507ddceee07SGeorge Liu getEfficiencyPercent(asyncResp); 50800ef5dc6SGeorge Liu } 50900ef5dc6SGeorge Liu 510bd79bce8SPatrick Williams inline void handlePowerSupplyHead( 511bd79bce8SPatrick Williams App& app, const crow::Request& req, 51200ef5dc6SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 513bd79bce8SPatrick Williams const std::string& chassisId, const std::string& powerSupplyId) 51400ef5dc6SGeorge Liu { 51500ef5dc6SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 51600ef5dc6SGeorge Liu { 51700ef5dc6SGeorge Liu return; 51800ef5dc6SGeorge Liu } 51900ef5dc6SGeorge Liu 52000ef5dc6SGeorge Liu // Get the correct Path and Service that match the input parameters 521bd79bce8SPatrick Williams getValidPowerSupplyPath( 5223e42a329SLakshmi Yadlapati asyncResp, chassisId, powerSupplyId, 523*193582b6SMyung Bae [asyncResp, powerSupplyId](const std::string& powerSupplyPath, 524*193582b6SMyung Bae const std::string& service) { 525*193582b6SMyung Bae if (powerSupplyPath.empty() || service.empty()) 526*193582b6SMyung Bae { 527*193582b6SMyung Bae BMCWEB_LOG_WARNING("PowerSupply not found"); 528*193582b6SMyung Bae messages::resourceNotFound(asyncResp->res, "PowerSupply", 529*193582b6SMyung Bae powerSupplyId); 530*193582b6SMyung Bae return; 531*193582b6SMyung Bae } 53200ef5dc6SGeorge Liu asyncResp->res.addHeader( 53300ef5dc6SGeorge Liu boost::beast::http::field::link, 53400ef5dc6SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby"); 53500ef5dc6SGeorge Liu }); 53600ef5dc6SGeorge Liu } 53700ef5dc6SGeorge Liu 538bd79bce8SPatrick Williams inline void handlePowerSupplyGet( 539bd79bce8SPatrick Williams App& app, const crow::Request& req, 54000ef5dc6SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 541bd79bce8SPatrick Williams const std::string& chassisId, const std::string& powerSupplyId) 54200ef5dc6SGeorge Liu { 54300ef5dc6SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 54400ef5dc6SGeorge Liu { 54500ef5dc6SGeorge Liu return; 54600ef5dc6SGeorge Liu } 5473e42a329SLakshmi Yadlapati getValidPowerSupplyPath( 5483e42a329SLakshmi Yadlapati asyncResp, chassisId, powerSupplyId, 54900ef5dc6SGeorge Liu std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId)); 55000ef5dc6SGeorge Liu } 55100ef5dc6SGeorge Liu 55200ef5dc6SGeorge Liu inline void requestRoutesPowerSupply(App& app) 55300ef5dc6SGeorge Liu { 55400ef5dc6SGeorge Liu BMCWEB_ROUTE( 55500ef5dc6SGeorge Liu app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/") 55600ef5dc6SGeorge Liu .privileges(redfish::privileges::headPowerSupply) 55700ef5dc6SGeorge Liu .methods(boost::beast::http::verb::head)( 55800ef5dc6SGeorge Liu std::bind_front(handlePowerSupplyHead, std::ref(app))); 55900ef5dc6SGeorge Liu 56000ef5dc6SGeorge Liu BMCWEB_ROUTE( 56100ef5dc6SGeorge Liu app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/") 56200ef5dc6SGeorge Liu .privileges(redfish::privileges::getPowerSupply) 56300ef5dc6SGeorge Liu .methods(boost::beast::http::verb::get)( 56400ef5dc6SGeorge Liu std::bind_front(handlePowerSupplyGet, std::ref(app))); 56500ef5dc6SGeorge Liu } 56600ef5dc6SGeorge Liu 567a7210020SGeorge Liu } // namespace redfish 568