From 42cbe53889b5f2d358d1174245df51a23efcb3f8 Mon Sep 17 00:00:00 2001 From: Gunnar Mills Date: Thu, 15 Aug 2019 15:26:54 -0500 Subject: Add Power Supply Attributes Map DeratingFactor from PowerSupplyAttributes.interface.yaml to the Redfish property PowerSupply "EfficiencyPercent". Only do this call when the "Power" schema is called. Use the InventoryItem class introduced in adc4f0db57568c5e5d2a3398fce00dbb050a3b72 Tested: Power, Thermal, all look good. Passed the Redfish Validator. "PowerSupplies": [ { "@odata.id": "/redfish/v1/Chassis/chassis/Power#/PowerSupplies/0", "EfficiencyPercent": 90, "IndicatorLED": "Off", "Manufacturer": "", "MemberId": "powersupply0", "Model": "2B1D", "Name": "powersupply0", "PartNumber": "01KL471", "PowerInputWatts": 12.0, "SerialNumber": "71G370", "Status": { "Health": "OK", "State": "Enabled" } }, Change-Id: I344577a7a3d72cd37d5f6bab03edbdce13b9f764 Signed-off-by: Gunnar Mills --- redfish-core/lib/sensors.hpp | 231 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 224 insertions(+), 7 deletions(-) (limited to 'redfish-core') diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp index 12657835d8..628e6ff6b6 100644 --- a/redfish-core/lib/sensors.hpp +++ b/redfish-core/lib/sensors.hpp @@ -93,8 +93,8 @@ class InventoryItem public: InventoryItem(const std::string& objPath) : objectPath(objPath), name(), isPresent(true), isFunctional(true), - isPowerSupply(false), manufacturer(), model(), partNumber(), - serialNumber(), sensors(), ledObjectPath(""), + isPowerSupply(false), powerSupplyEfficiencyPercent(-1), manufacturer(), + model(), partNumber(), serialNumber(), sensors(), ledObjectPath(""), ledState(LedState::UNKNOWN) { // Set inventory item name to last node of object path @@ -110,6 +110,7 @@ class InventoryItem bool isPresent; bool isFunctional; bool isPowerSupply; + int powerSupplyEfficiencyPercent; std::string manufacturer; std::string model; std::string partNumber; @@ -1758,7 +1759,7 @@ static void getInventoryItemAssociations( * * The callback must have the following signature: * @code - * callback(std::shared_ptr> inventoryItems) + * callback() * @endcode * * This function is called recursively, obtaining data asynchronously from one @@ -1785,7 +1786,7 @@ void getInventoryLedData( // If no more connections left, call callback if (ledConnectionsIndex >= ledConnections->size()) { - callback(inventoryItems); + callback(); BMCWEB_LOG_DEBUG << "getInventoryLedData exit"; return; } @@ -1878,7 +1879,7 @@ void getInventoryLedData( * * The callback must have the following signature: * @code - * callback(std::shared_ptr> inventoryItems) + * callback() * @endcode * * @param sensorsAsyncResp Pointer to object holding response data. @@ -1946,6 +1947,203 @@ void getInventoryLeds( BMCWEB_LOG_DEBUG << "getInventoryLeds exit"; } +/** + * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent + * + * Uses the specified connections (services) (currently assumes just one) to + * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in + * the inventoryItems vector. Only stores data in Power Supply inventoryItems. + * + * This data is later used to provide sensor property values in the JSON + * response. + * + * Finds the Power Supply Attributes data asynchronously. Invokes callback + * when data has been obtained. + * + * The callback must have the following signature: + * @code + * callback(std::shared_ptr> inventoryItems) + * @endcode + * + * @param sensorsAsyncResp Pointer to object holding response data. + * @param inventoryItems D-Bus inventory items associated with sensors. + * @param psAttributesConnections Connections that provide data for the Power + * Supply Attributes + * @param callback Callback to invoke when data has been obtained. + */ +template +void getPowerSupplyAttributesData( + std::shared_ptr sensorsAsyncResp, + std::shared_ptr> inventoryItems, + const boost::container::flat_map& + psAttributesConnections, + Callback&& callback) +{ + BMCWEB_LOG_DEBUG << "getPowerSupplyAttributesData enter"; + + if (psAttributesConnections.empty()) + { + BMCWEB_LOG_DEBUG << "Can't find PowerSupplyAttributes, no connections!"; + callback(inventoryItems); + return; + } + + // Assuming just one connection (service) for now + auto it = psAttributesConnections.nth(0); + + const std::string& psAttributesPath = (*it).first; + const std::string& psAttributesConnection = (*it).second; + + // Response handler for Get DeratingFactor property + auto respHandler = [sensorsAsyncResp, inventoryItems, + callback{std::move(callback)}]( + const boost::system::error_code ec, + const std::variant& deratingFactor) { + BMCWEB_LOG_DEBUG << "getPowerSupplyAttributesData respHandler enter"; + if (ec) + { + BMCWEB_LOG_ERROR + << "getPowerSupplyAttributesData respHandler DBus error " << ec; + messages::internalError(sensorsAsyncResp->res); + return; + } + + const uint32_t* value = std::get_if(&deratingFactor); + if (value != nullptr) + { + BMCWEB_LOG_DEBUG << "PS EfficiencyPercent value: " << *value; + // Store value in Power Supply Inventory Items + for (InventoryItem& inventoryItem : *inventoryItems) + { + if (inventoryItem.isPowerSupply == true) + { + inventoryItem.powerSupplyEfficiencyPercent = + static_cast(*value); + } + } + } + else + { + BMCWEB_LOG_DEBUG + << "Failed to find EfficiencyPercent value for PowerSupplies"; + } + + BMCWEB_LOG_DEBUG << "getPowerSupplyAttributesData respHandler exit"; + callback(inventoryItems); + }; + + // Get the DeratingFactor property for the PowerSupplyAttributes + // Currently only property on the interface/only one we care about + crow::connections::systemBus->async_method_call( + std::move(respHandler), psAttributesConnection, psAttributesPath, + "org.freedesktop.DBus.Properties", "Get", + "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor"); + + BMCWEB_LOG_DEBUG << "getPowerSupplyAttributesData exit"; +} + +/** + * @brief Gets the Power Supply Attributes such as EfficiencyPercent + * + * Gets the D-Bus connection (service) that provides Power Supply Attributes + * data. Then gets the Power Supply Attributes data from the connection + * (currently just assumes 1 connection) and stores the data in the inventory + * item. + * + * This data is later used to provide sensor property values in the JSON + * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish. + * + * Finds the Power Supply Attributes data asynchronously. Invokes callback + * when information has been obtained. + * + * The callback must have the following signature: + * @code + * callback(std::shared_ptr> inventoryItems) + * @endcode + * + * @param sensorsAsyncResp Pointer to object holding response data. + * @param inventoryItems D-Bus inventory items associated with sensors. + * @param callback Callback to invoke when data has been obtained. + */ +template +void getPowerSupplyAttributes( + std::shared_ptr sensorsAsyncResp, + std::shared_ptr> inventoryItems, + Callback&& callback) +{ + BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes enter"; + + // Only need the power supply attributes when the Power Schema + if (sensorsAsyncResp->chassisSubNode != "Power") + { + BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes exit since not Power"; + callback(inventoryItems); + return; + } + + const std::array interfaces = { + "xyz.openbmc_project.Control.PowerSupplyAttributes"}; + + // Response handler for parsing output from GetSubTree + auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp, + inventoryItems](const boost::system::error_code ec, + const GetSubTreeType& subtree) { + BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes respHandler enter"; + if (ec) + { + messages::internalError(sensorsAsyncResp->res); + BMCWEB_LOG_ERROR + << "getPowerSupplyAttributes respHandler DBus error " << ec; + return; + } + if (subtree.size() == 0) + { + BMCWEB_LOG_DEBUG << "Can't find Power Supply Attributes!"; + callback(inventoryItems); + return; + } + + // Currently we only support 1 power supply attribute, use this for + // all the power supplies. Build map of object path to connection. + // Assume just 1 connection and 1 path for now. + boost::container::flat_map + psAttributesConnections; + + if (subtree[0].first.empty() || subtree[0].second.empty()) + { + BMCWEB_LOG_DEBUG << "Power Supply Attributes mapper error!"; + callback(inventoryItems); + return; + } + + const std::string& psAttributesPath = subtree[0].first; + const std::string& connection = subtree[0].second.begin()->first; + + if (connection.empty()) + { + BMCWEB_LOG_DEBUG << "Power Supply Attributes mapper error!"; + callback(inventoryItems); + return; + } + + psAttributesConnections[psAttributesPath] = connection; + BMCWEB_LOG_DEBUG << "Added mapping " << psAttributesPath << " -> " + << connection; + + getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems, + psAttributesConnections, + std::move(callback)); + BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes respHandler exit"; + }; + // Make call to ObjectMapper to find the PowerSupplyAttributes service + crow::connections::systemBus->async_method_call( + std::move(respHandler), "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTree", + "/xyz/openbmc_project", 0, interfaces); + BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes exit"; +} + /** * @brief Gets inventory items associated with sensors. * @@ -1992,9 +2190,22 @@ static void getInventoryItems( [sensorsAsyncResp, inventoryItems, callback{std::move(callback)}]() { BMCWEB_LOG_DEBUG << "getInventoryItemsDataCb enter"; + + auto getInventoryLedsCb = [sensorsAsyncResp, + inventoryItems, + callback{std::move( + callback)}]() { + BMCWEB_LOG_DEBUG << "getInventoryLedsCb enter"; + // Find Power Supply Attributes and get the data + getPowerSupplyAttributes(sensorsAsyncResp, + inventoryItems, + std::move(callback)); + BMCWEB_LOG_DEBUG << "getInventoryLedsCb exit"; + }; + // Find led connections and get the data getInventoryLeds(sensorsAsyncResp, inventoryItems, - std::move(callback)); + std::move(getInventoryLedsCb)); BMCWEB_LOG_DEBUG << "getInventoryItemsDataCb exit"; }; @@ -2059,8 +2270,14 @@ static nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray, powerSupply["PartNumber"] = inventoryItem.partNumber; powerSupply["SerialNumber"] = inventoryItem.serialNumber; setLedState(powerSupply, &inventoryItem); - powerSupply["Status"]["State"] = getState(&inventoryItem); + if (inventoryItem.powerSupplyEfficiencyPercent >= 0) + { + powerSupply["EfficiencyPercent"] = + inventoryItem.powerSupplyEfficiencyPercent; + } + + powerSupply["Status"]["State"] = getState(&inventoryItem); const char* health = inventoryItem.isFunctional ? "OK" : "Critical"; powerSupply["Status"]["Health"] = health; -- cgit v1.2.3