108777fb0SLewanczyk, Dawid /* 26be832e2SEd Tanous Copyright (c) 2018 Intel Corporation 36be832e2SEd Tanous 46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License"); 56be832e2SEd Tanous you may not use this file except in compliance with the License. 66be832e2SEd Tanous You may obtain a copy of the License at 76be832e2SEd Tanous 86be832e2SEd Tanous http://www.apache.org/licenses/LICENSE-2.0 96be832e2SEd Tanous 106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software 116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS, 126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136be832e2SEd Tanous See the License for the specific language governing permissions and 146be832e2SEd Tanous limitations under the License. 1508777fb0SLewanczyk, Dawid */ 1608777fb0SLewanczyk, Dawid #pragma once 1708777fb0SLewanczyk, Dawid 183ccb3adbSEd Tanous #include "app.hpp" 193ccb3adbSEd Tanous #include "dbus_singleton.hpp" 207a1dbc48SGeorge Liu #include "dbus_utility.hpp" 21539d8c6bSEd Tanous #include "generated/enums/redundancy.hpp" 22aaf08ac7SMatt Simmering #include "generated/enums/resource.hpp" 233ccb3adbSEd Tanous #include "query.hpp" 243ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 2550ebd4afSEd Tanous #include "str_utility.hpp" 263ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 273ccb3adbSEd Tanous #include "utils/json_utils.hpp" 283ccb3adbSEd Tanous #include "utils/query_param.hpp" 291516c21bSJanet Adkins #include "utils/sensor_utils.hpp" 300ec8b83dSEd Tanous 31e99073f5SGeorge Liu #include <boost/system/error_code.hpp> 32ef4c65b7SEd Tanous #include <boost/url/format.hpp> 331e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp> 3486d89ed7SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 351214b7e7SGunnar Mills 367a1dbc48SGeorge Liu #include <array> 371214b7e7SGunnar Mills #include <cmath> 38fe04d49cSNan Zhou #include <iterator> 39283860f5SEd Tanous #include <limits> 40fe04d49cSNan Zhou #include <map> 413544d2a7SEd Tanous #include <ranges> 42fe04d49cSNan Zhou #include <set> 4318f8f608SEd Tanous #include <string> 447a1dbc48SGeorge Liu #include <string_view> 45b5a76932SEd Tanous #include <utility> 46abf2add6SEd Tanous #include <variant> 4708777fb0SLewanczyk, Dawid 481abe55efSEd Tanous namespace redfish 491abe55efSEd Tanous { 5008777fb0SLewanczyk, Dawid 51a0ec28b6SAdrian Ambrożewicz namespace sensors 52a0ec28b6SAdrian Ambrożewicz { 53a0ec28b6SAdrian Ambrożewicz 5402da7c5aSEd Tanous // clang-format off 55a0ec28b6SAdrian Ambrożewicz namespace dbus 56a0ec28b6SAdrian Ambrożewicz { 57cf9e417dSEd Tanous constexpr auto powerPaths = std::to_array<std::string_view>({ 5802da7c5aSEd Tanous "/xyz/openbmc_project/sensors/voltage", 5902da7c5aSEd Tanous "/xyz/openbmc_project/sensors/power" 6002da7c5aSEd Tanous }); 61c2bf7f99SWludzik, Jozef 6225b54dbaSEd Tanous constexpr auto getSensorPaths(){ 6325b54dbaSEd Tanous if constexpr(BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM){ 6425b54dbaSEd Tanous return std::to_array<std::string_view>({ 6502da7c5aSEd Tanous "/xyz/openbmc_project/sensors/power", 66a0ec28b6SAdrian Ambrożewicz "/xyz/openbmc_project/sensors/current", 677088690cSBasheer Ahmed Muddebihal "/xyz/openbmc_project/sensors/airflow", 685deabed9SGunnar Mills "/xyz/openbmc_project/sensors/humidity", 69e8204933SGeorge Liu "/xyz/openbmc_project/sensors/voltage", 70e8204933SGeorge Liu "/xyz/openbmc_project/sensors/fan_tach", 71e8204933SGeorge Liu "/xyz/openbmc_project/sensors/temperature", 72e8204933SGeorge Liu "/xyz/openbmc_project/sensors/fan_pwm", 73e8204933SGeorge Liu "/xyz/openbmc_project/sensors/altitude", 74e8204933SGeorge Liu "/xyz/openbmc_project/sensors/energy", 7525b54dbaSEd Tanous "/xyz/openbmc_project/sensors/utilization"}); 7625b54dbaSEd Tanous } else { 7725b54dbaSEd Tanous return std::to_array<std::string_view>({"/xyz/openbmc_project/sensors/power", 7825b54dbaSEd Tanous "/xyz/openbmc_project/sensors/current", 7925b54dbaSEd Tanous "/xyz/openbmc_project/sensors/airflow", 8025b54dbaSEd Tanous "/xyz/openbmc_project/sensors/humidity", 8125b54dbaSEd Tanous "/xyz/openbmc_project/sensors/utilization"}); 8225b54dbaSEd Tanous } 8325b54dbaSEd Tanous } 8425b54dbaSEd Tanous 8525b54dbaSEd Tanous constexpr auto sensorPaths = getSensorPaths(); 8602da7c5aSEd Tanous 87cf9e417dSEd Tanous constexpr auto thermalPaths = std::to_array<std::string_view>({ 8802da7c5aSEd Tanous "/xyz/openbmc_project/sensors/fan_tach", 89a0ec28b6SAdrian Ambrożewicz "/xyz/openbmc_project/sensors/temperature", 9002da7c5aSEd Tanous "/xyz/openbmc_project/sensors/fan_pwm" 9102da7c5aSEd Tanous }); 9202da7c5aSEd Tanous 93c2bf7f99SWludzik, Jozef } // namespace dbus 9402da7c5aSEd Tanous // clang-format on 9502da7c5aSEd Tanous 960c728b42SJanet Adkins constexpr std::string_view powerNodeStr = sensor_utils::chassisSubNodeToString( 970c728b42SJanet Adkins sensor_utils::ChassisSubNode::powerNode); 980c728b42SJanet Adkins constexpr std::string_view sensorsNodeStr = 990c728b42SJanet Adkins sensor_utils::chassisSubNodeToString( 1000c728b42SJanet Adkins sensor_utils::ChassisSubNode::sensorsNode); 1010c728b42SJanet Adkins constexpr std::string_view thermalNodeStr = 1020c728b42SJanet Adkins sensor_utils::chassisSubNodeToString( 1030c728b42SJanet Adkins sensor_utils::ChassisSubNode::thermalNode); 1040c728b42SJanet Adkins 105cf9e417dSEd Tanous using sensorPair = 106cf9e417dSEd Tanous std::pair<std::string_view, std::span<const std::string_view>>; 10702da7c5aSEd Tanous static constexpr std::array<sensorPair, 3> paths = { 1080c728b42SJanet Adkins {{sensors::powerNodeStr, dbus::powerPaths}, 1090c728b42SJanet Adkins {sensors::sensorsNodeStr, dbus::sensorPaths}, 1100c728b42SJanet Adkins {sensors::thermalNodeStr, dbus::thermalPaths}}}; 111c2bf7f99SWludzik, Jozef 112a0ec28b6SAdrian Ambrożewicz } // namespace sensors 113a0ec28b6SAdrian Ambrożewicz 11408777fb0SLewanczyk, Dawid /** 115588c3f0dSKowalski, Kamil * SensorsAsyncResp 11608777fb0SLewanczyk, Dawid * Gathers data needed for response processing after async calls are done 11708777fb0SLewanczyk, Dawid */ 1181abe55efSEd Tanous class SensorsAsyncResp 1191abe55efSEd Tanous { 12008777fb0SLewanczyk, Dawid public: 121a0ec28b6SAdrian Ambrożewicz using DataCompleteCb = std::function<void( 122a0ec28b6SAdrian Ambrożewicz const boost::beast::http::status status, 123fe04d49cSNan Zhou const std::map<std::string, std::string>& uriToDbus)>; 124a0ec28b6SAdrian Ambrożewicz 125a0ec28b6SAdrian Ambrożewicz struct SensorData 126a0ec28b6SAdrian Ambrożewicz { 127f836c1d8SEd Tanous std::string name; 128a0ec28b6SAdrian Ambrożewicz std::string uri; 129f836c1d8SEd Tanous std::string dbusPath; 130a0ec28b6SAdrian Ambrożewicz }; 131a0ec28b6SAdrian Ambrożewicz 1328a592810SEd Tanous SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn, 1338d1b46d7Szhanghch05 const std::string& chassisIdIn, 134cf9e417dSEd Tanous std::span<const std::string_view> typesIn, 13502da7c5aSEd Tanous std::string_view subNode) : 136bd79bce8SPatrick Williams asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn), 137bd79bce8SPatrick Williams chassisSubNode(subNode), efficientExpand(false) 1381214b7e7SGunnar Mills {} 13908777fb0SLewanczyk, Dawid 140a0ec28b6SAdrian Ambrożewicz // Store extra data about sensor mapping and return it in callback 1418a592810SEd Tanous SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn, 1428d1b46d7Szhanghch05 const std::string& chassisIdIn, 143cf9e417dSEd Tanous std::span<const std::string_view> typesIn, 14402da7c5aSEd Tanous std::string_view subNode, 145a0ec28b6SAdrian Ambrożewicz DataCompleteCb&& creationComplete) : 146bd79bce8SPatrick Williams asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn), 147bd79bce8SPatrick Williams chassisSubNode(subNode), efficientExpand(false), 148bd79bce8SPatrick Williams metadata{std::vector<SensorData>()}, 149a0ec28b6SAdrian Ambrożewicz dataComplete{std::move(creationComplete)} 150a0ec28b6SAdrian Ambrożewicz {} 151a0ec28b6SAdrian Ambrożewicz 152928fefb9SNan Zhou // sensor collections expand 1538a592810SEd Tanous SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn, 154928fefb9SNan Zhou const std::string& chassisIdIn, 155cf9e417dSEd Tanous std::span<const std::string_view> typesIn, 1568a592810SEd Tanous const std::string_view& subNode, bool efficientExpandIn) : 157bd79bce8SPatrick Williams asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn), 158bd79bce8SPatrick Williams chassisSubNode(subNode), efficientExpand(efficientExpandIn) 159928fefb9SNan Zhou {} 160928fefb9SNan Zhou 1611abe55efSEd Tanous ~SensorsAsyncResp() 1621abe55efSEd Tanous { 1638d1b46d7Szhanghch05 if (asyncResp->res.result() == 1648d1b46d7Szhanghch05 boost::beast::http::status::internal_server_error) 1651abe55efSEd Tanous { 1661abe55efSEd Tanous // Reset the json object to clear out any data that made it in 1671abe55efSEd Tanous // before the error happened todo(ed) handle error condition with 1681abe55efSEd Tanous // proper code 1698d1b46d7Szhanghch05 asyncResp->res.jsonValue = nlohmann::json::object(); 17008777fb0SLewanczyk, Dawid } 171a0ec28b6SAdrian Ambrożewicz 172a0ec28b6SAdrian Ambrożewicz if (dataComplete && metadata) 173a0ec28b6SAdrian Ambrożewicz { 174fe04d49cSNan Zhou std::map<std::string, std::string> map; 1758d1b46d7Szhanghch05 if (asyncResp->res.result() == boost::beast::http::status::ok) 176a0ec28b6SAdrian Ambrożewicz { 177a0ec28b6SAdrian Ambrożewicz for (auto& sensor : *metadata) 178a0ec28b6SAdrian Ambrożewicz { 179c1d019a6SEd Tanous map.emplace(sensor.uri, sensor.dbusPath); 180a0ec28b6SAdrian Ambrożewicz } 181a0ec28b6SAdrian Ambrożewicz } 1828d1b46d7Szhanghch05 dataComplete(asyncResp->res.result(), map); 183a0ec28b6SAdrian Ambrożewicz } 18408777fb0SLewanczyk, Dawid } 185588c3f0dSKowalski, Kamil 186ecd6a3a2SEd Tanous SensorsAsyncResp(const SensorsAsyncResp&) = delete; 187ecd6a3a2SEd Tanous SensorsAsyncResp(SensorsAsyncResp&&) = delete; 188ecd6a3a2SEd Tanous SensorsAsyncResp& operator=(const SensorsAsyncResp&) = delete; 189ecd6a3a2SEd Tanous SensorsAsyncResp& operator=(SensorsAsyncResp&&) = delete; 190ecd6a3a2SEd Tanous 191a0ec28b6SAdrian Ambrożewicz void addMetadata(const nlohmann::json& sensorObject, 192c1d019a6SEd Tanous const std::string& dbusPath) 193a0ec28b6SAdrian Ambrożewicz { 194a0ec28b6SAdrian Ambrożewicz if (metadata) 195a0ec28b6SAdrian Ambrożewicz { 196c1d019a6SEd Tanous metadata->emplace_back(SensorData{ 197c1d019a6SEd Tanous sensorObject["Name"], sensorObject["@odata.id"], dbusPath}); 198a0ec28b6SAdrian Ambrożewicz } 199a0ec28b6SAdrian Ambrożewicz } 200a0ec28b6SAdrian Ambrożewicz 201a0ec28b6SAdrian Ambrożewicz void updateUri(const std::string& name, const std::string& uri) 202a0ec28b6SAdrian Ambrożewicz { 203a0ec28b6SAdrian Ambrożewicz if (metadata) 204a0ec28b6SAdrian Ambrożewicz { 205a0ec28b6SAdrian Ambrożewicz for (auto& sensor : *metadata) 206a0ec28b6SAdrian Ambrożewicz { 207a0ec28b6SAdrian Ambrożewicz if (sensor.name == name) 208a0ec28b6SAdrian Ambrożewicz { 209a0ec28b6SAdrian Ambrożewicz sensor.uri = uri; 210a0ec28b6SAdrian Ambrożewicz } 211a0ec28b6SAdrian Ambrożewicz } 212a0ec28b6SAdrian Ambrożewicz } 213a0ec28b6SAdrian Ambrożewicz } 214a0ec28b6SAdrian Ambrożewicz 2158d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp> asyncResp; 216a0ec28b6SAdrian Ambrożewicz const std::string chassisId; 217cf9e417dSEd Tanous const std::span<const std::string_view> types; 218a0ec28b6SAdrian Ambrożewicz const std::string chassisSubNode; 219928fefb9SNan Zhou const bool efficientExpand; 220a0ec28b6SAdrian Ambrożewicz 221a0ec28b6SAdrian Ambrożewicz private: 222a0ec28b6SAdrian Ambrożewicz std::optional<std::vector<SensorData>> metadata; 223a0ec28b6SAdrian Ambrożewicz DataCompleteCb dataComplete; 22408777fb0SLewanczyk, Dawid }; 22508777fb0SLewanczyk, Dawid 226c9563608SJanet Adkins using InventoryItem = sensor_utils::InventoryItem; 227adc4f0dbSShawn McCarney 228adc4f0dbSShawn McCarney /** 229413961deSRichard Marian Thomaiyar * @brief Get objects with connection necessary for sensors 230588c3f0dSKowalski, Kamil * @param SensorsAsyncResp Pointer to object holding response data 23108777fb0SLewanczyk, Dawid * @param sensorNames Sensors retrieved from chassis 23208777fb0SLewanczyk, Dawid * @param callback Callback for processing gathered connections 23308777fb0SLewanczyk, Dawid */ 23408777fb0SLewanczyk, Dawid template <typename Callback> 235413961deSRichard Marian Thomaiyar void getObjectsWithConnection( 23681ce609eSEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp, 237fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& sensorNames, 2381abe55efSEd Tanous Callback&& callback) 2391abe55efSEd Tanous { 24062598e31SEd Tanous BMCWEB_LOG_DEBUG("getObjectsWithConnection enter"); 24103b5bae3SJames Feist const std::string path = "/xyz/openbmc_project/sensors"; 242e99073f5SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 24308777fb0SLewanczyk, Dawid "xyz.openbmc_project.Sensor.Value"}; 24408777fb0SLewanczyk, Dawid 245e99073f5SGeorge Liu // Make call to ObjectMapper to find all sensors objects 246e99073f5SGeorge Liu dbus::utility::getSubTree( 247e99073f5SGeorge Liu path, 2, interfaces, 2488cb2c024SEd Tanous [callback = std::forward<Callback>(callback), sensorsAsyncResp, 249e99073f5SGeorge Liu sensorNames](const boost::system::error_code& ec, 250002d39b4SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 251e99073f5SGeorge Liu // Response handler for parsing objects subtree 25262598e31SEd Tanous BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler enter"); 2531abe55efSEd Tanous if (ec) 2541abe55efSEd Tanous { 2558d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 25662598e31SEd Tanous BMCWEB_LOG_ERROR( 25762598e31SEd Tanous "getObjectsWithConnection resp_handler: Dbus error {}", ec); 25808777fb0SLewanczyk, Dawid return; 25908777fb0SLewanczyk, Dawid } 26008777fb0SLewanczyk, Dawid 26162598e31SEd Tanous BMCWEB_LOG_DEBUG("Found {} subtrees", subtree.size()); 26208777fb0SLewanczyk, Dawid 263bd79bce8SPatrick Williams // Make unique list of connections only for requested sensor types 264bd79bce8SPatrick Williams // and found in the chassis 265fe04d49cSNan Zhou std::set<std::string> connections; 266413961deSRichard Marian Thomaiyar std::set<std::pair<std::string, std::string>> objectsWithConnection; 26708777fb0SLewanczyk, Dawid 26862598e31SEd Tanous BMCWEB_LOG_DEBUG("sensorNames list count: {}", sensorNames->size()); 26949c53ac9SJohnathan Mantey for (const std::string& tsensor : *sensorNames) 2701abe55efSEd Tanous { 27162598e31SEd Tanous BMCWEB_LOG_DEBUG("Sensor to find: {}", tsensor); 27208777fb0SLewanczyk, Dawid } 27308777fb0SLewanczyk, Dawid 274bd79bce8SPatrick Williams for (const std::pair<std::string, 275bd79bce8SPatrick Williams std::vector<std::pair< 276bd79bce8SPatrick Williams std::string, std::vector<std::string>>>>& 2771abe55efSEd Tanous object : subtree) 2781abe55efSEd Tanous { 27949c53ac9SJohnathan Mantey if (sensorNames->find(object.first) != sensorNames->end()) 2801abe55efSEd Tanous { 28149c53ac9SJohnathan Mantey for (const std::pair<std::string, std::vector<std::string>>& 2821abe55efSEd Tanous objData : object.second) 2831abe55efSEd Tanous { 284bd79bce8SPatrick Williams BMCWEB_LOG_DEBUG("Adding connection: {}", 285bd79bce8SPatrick Williams objData.first); 28608777fb0SLewanczyk, Dawid connections.insert(objData.first); 287de629b6eSShawn McCarney objectsWithConnection.insert( 288de629b6eSShawn McCarney std::make_pair(object.first, objData.first)); 28908777fb0SLewanczyk, Dawid } 29008777fb0SLewanczyk, Dawid } 29108777fb0SLewanczyk, Dawid } 29262598e31SEd Tanous BMCWEB_LOG_DEBUG("Found {} connections", connections.size()); 293413961deSRichard Marian Thomaiyar callback(std::move(connections), std::move(objectsWithConnection)); 29462598e31SEd Tanous BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler exit"); 295e99073f5SGeorge Liu }); 29662598e31SEd Tanous BMCWEB_LOG_DEBUG("getObjectsWithConnection exit"); 297413961deSRichard Marian Thomaiyar } 298413961deSRichard Marian Thomaiyar 299413961deSRichard Marian Thomaiyar /** 300413961deSRichard Marian Thomaiyar * @brief Create connections necessary for sensors 301413961deSRichard Marian Thomaiyar * @param SensorsAsyncResp Pointer to object holding response data 302413961deSRichard Marian Thomaiyar * @param sensorNames Sensors retrieved from chassis 303413961deSRichard Marian Thomaiyar * @param callback Callback for processing gathered connections 304413961deSRichard Marian Thomaiyar */ 305413961deSRichard Marian Thomaiyar template <typename Callback> 306fe04d49cSNan Zhou void getConnections(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 307fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>> sensorNames, 308413961deSRichard Marian Thomaiyar Callback&& callback) 309413961deSRichard Marian Thomaiyar { 310413961deSRichard Marian Thomaiyar auto objectsWithConnectionCb = 3118cb2c024SEd Tanous [callback = std::forward<Callback>(callback)]( 3128cb2c024SEd Tanous const std::set<std::string>& connections, 313413961deSRichard Marian Thomaiyar const std::set<std::pair<std::string, std::string>>& 3143174e4dfSEd Tanous /*objectsWithConnection*/) { callback(connections); }; 31581ce609eSEd Tanous getObjectsWithConnection(sensorsAsyncResp, sensorNames, 316413961deSRichard Marian Thomaiyar std::move(objectsWithConnectionCb)); 31708777fb0SLewanczyk, Dawid } 31808777fb0SLewanczyk, Dawid 31908777fb0SLewanczyk, Dawid /** 32049c53ac9SJohnathan Mantey * @brief Shrinks the list of sensors for processing 32149c53ac9SJohnathan Mantey * @param SensorsAysncResp The class holding the Redfish response 32249c53ac9SJohnathan Mantey * @param allSensors A list of all the sensors associated to the 32349c53ac9SJohnathan Mantey * chassis element (i.e. baseboard, front panel, etc...) 32449c53ac9SJohnathan Mantey * @param activeSensors A list that is a reduction of the incoming 32549c53ac9SJohnathan Mantey * allSensors list. Eliminate Thermal sensors when a Power request is 32649c53ac9SJohnathan Mantey * made, and eliminate Power sensors when a Thermal request is made. 32749c53ac9SJohnathan Mantey */ 32823a21a1cSEd Tanous inline void reduceSensorList( 3297f1cc26dSEd Tanous crow::Response& res, std::string_view chassisSubNode, 330cf9e417dSEd Tanous std::span<const std::string_view> sensorTypes, 33149c53ac9SJohnathan Mantey const std::vector<std::string>* allSensors, 332fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& activeSensors) 33349c53ac9SJohnathan Mantey { 33449c53ac9SJohnathan Mantey if ((allSensors == nullptr) || (activeSensors == nullptr)) 33549c53ac9SJohnathan Mantey { 3367f1cc26dSEd Tanous messages::resourceNotFound(res, chassisSubNode, 3370c728b42SJanet Adkins chassisSubNode == sensors::thermalNodeStr 338a0ec28b6SAdrian Ambrożewicz ? "Temperatures" 33949c53ac9SJohnathan Mantey : "Voltages"); 34049c53ac9SJohnathan Mantey 34149c53ac9SJohnathan Mantey return; 34249c53ac9SJohnathan Mantey } 34349c53ac9SJohnathan Mantey if (allSensors->empty()) 34449c53ac9SJohnathan Mantey { 34549c53ac9SJohnathan Mantey // Nothing to do, the activeSensors object is also empty 34649c53ac9SJohnathan Mantey return; 34749c53ac9SJohnathan Mantey } 34849c53ac9SJohnathan Mantey 3497f1cc26dSEd Tanous for (std::string_view type : sensorTypes) 35049c53ac9SJohnathan Mantey { 35149c53ac9SJohnathan Mantey for (const std::string& sensor : *allSensors) 35249c53ac9SJohnathan Mantey { 35311ba3979SEd Tanous if (sensor.starts_with(type)) 35449c53ac9SJohnathan Mantey { 35549c53ac9SJohnathan Mantey activeSensors->emplace(sensor); 35649c53ac9SJohnathan Mantey } 35749c53ac9SJohnathan Mantey } 35849c53ac9SJohnathan Mantey } 35949c53ac9SJohnathan Mantey } 36049c53ac9SJohnathan Mantey 3617f1cc26dSEd Tanous /* 3627f1cc26dSEd Tanous *Populates the top level collection for a given subnode. Populates 3637f1cc26dSEd Tanous *SensorCollection, Power, or Thermal schemas. 3647f1cc26dSEd Tanous * 3657f1cc26dSEd Tanous * */ 3667f1cc26dSEd Tanous inline void populateChassisNode(nlohmann::json& jsonValue, 3677f1cc26dSEd Tanous std::string_view chassisSubNode) 3687f1cc26dSEd Tanous { 3690c728b42SJanet Adkins if (chassisSubNode == sensors::powerNodeStr) 3707f1cc26dSEd Tanous { 3717f1cc26dSEd Tanous jsonValue["@odata.type"] = "#Power.v1_5_2.Power"; 3727f1cc26dSEd Tanous } 3730c728b42SJanet Adkins else if (chassisSubNode == sensors::thermalNodeStr) 3747f1cc26dSEd Tanous { 3757f1cc26dSEd Tanous jsonValue["@odata.type"] = "#Thermal.v1_4_0.Thermal"; 3767f1cc26dSEd Tanous jsonValue["Fans"] = nlohmann::json::array(); 3777f1cc26dSEd Tanous jsonValue["Temperatures"] = nlohmann::json::array(); 3787f1cc26dSEd Tanous } 3790c728b42SJanet Adkins else if (chassisSubNode == sensors::sensorsNodeStr) 3807f1cc26dSEd Tanous { 3817f1cc26dSEd Tanous jsonValue["@odata.type"] = "#SensorCollection.SensorCollection"; 3827f1cc26dSEd Tanous jsonValue["Description"] = "Collection of Sensors for this Chassis"; 3837f1cc26dSEd Tanous jsonValue["Members"] = nlohmann::json::array(); 3847f1cc26dSEd Tanous jsonValue["Members@odata.count"] = 0; 3857f1cc26dSEd Tanous } 3867f1cc26dSEd Tanous 3870c728b42SJanet Adkins if (chassisSubNode != sensors::sensorsNodeStr) 3887f1cc26dSEd Tanous { 3897f1cc26dSEd Tanous jsonValue["Id"] = chassisSubNode; 3907f1cc26dSEd Tanous } 3917f1cc26dSEd Tanous jsonValue["Name"] = chassisSubNode; 3927f1cc26dSEd Tanous } 3937f1cc26dSEd Tanous 39449c53ac9SJohnathan Mantey /** 39508777fb0SLewanczyk, Dawid * @brief Retrieves requested chassis sensors and redundancy data from DBus . 396588c3f0dSKowalski, Kamil * @param SensorsAsyncResp Pointer to object holding response data 39708777fb0SLewanczyk, Dawid * @param callback Callback for next step in gathered sensor processing 39808777fb0SLewanczyk, Dawid */ 39908777fb0SLewanczyk, Dawid template <typename Callback> 4007f1cc26dSEd Tanous void getChassis(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4017f1cc26dSEd Tanous std::string_view chassisId, std::string_view chassisSubNode, 402cf9e417dSEd Tanous std::span<const std::string_view> sensorTypes, 403cf9e417dSEd Tanous Callback&& callback) 4041abe55efSEd Tanous { 40562598e31SEd Tanous BMCWEB_LOG_DEBUG("getChassis enter"); 4067a1dbc48SGeorge Liu constexpr std::array<std::string_view, 2> interfaces = { 40749c53ac9SJohnathan Mantey "xyz.openbmc_project.Inventory.Item.Board", 408adc4f0dbSShawn McCarney "xyz.openbmc_project.Inventory.Item.Chassis"}; 4097a1dbc48SGeorge Liu 4107a1dbc48SGeorge Liu // Get the Chassis Collection 4117a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 4127a1dbc48SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 4138cb2c024SEd Tanous [callback = std::forward<Callback>(callback), asyncResp, 4147f1cc26dSEd Tanous chassisIdStr{std::string(chassisId)}, 4154e0d8789SEd Tanous chassisSubNode{std::string(chassisSubNode)}, 4164e0d8789SEd Tanous sensorTypes](const boost::system::error_code& ec, 4174e0d8789SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 4184e0d8789SEd Tanous chassisPaths) mutable { 41962598e31SEd Tanous BMCWEB_LOG_DEBUG("getChassis respHandler enter"); 4201abe55efSEd Tanous if (ec) 4211abe55efSEd Tanous { 42262598e31SEd Tanous BMCWEB_LOG_ERROR("getChassis respHandler DBUS error: {}", ec); 4237f1cc26dSEd Tanous messages::internalError(asyncResp->res); 42408777fb0SLewanczyk, Dawid return; 42508777fb0SLewanczyk, Dawid } 42649c53ac9SJohnathan Mantey const std::string* chassisPath = nullptr; 42749c53ac9SJohnathan Mantey for (const std::string& chassis : chassisPaths) 4281abe55efSEd Tanous { 42928aa8de5SGeorge Liu sdbusplus::message::object_path path(chassis); 430f8fe53e7SEd Tanous std::string chassisName = path.filename(); 43128aa8de5SGeorge Liu if (chassisName.empty()) 4321abe55efSEd Tanous { 43362598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to find '/' in {}", chassis); 434daf36e2eSEd Tanous continue; 435daf36e2eSEd Tanous } 4367f1cc26dSEd Tanous if (chassisName == chassisIdStr) 4371abe55efSEd Tanous { 43849c53ac9SJohnathan Mantey chassisPath = &chassis; 43949c53ac9SJohnathan Mantey break; 440daf36e2eSEd Tanous } 44149c53ac9SJohnathan Mantey } 44249c53ac9SJohnathan Mantey if (chassisPath == nullptr) 4431abe55efSEd Tanous { 444bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Chassis", 445bd79bce8SPatrick Williams chassisIdStr); 44649c53ac9SJohnathan Mantey return; 4471abe55efSEd Tanous } 4487f1cc26dSEd Tanous populateChassisNode(asyncResp->res.jsonValue, chassisSubNode); 44908777fb0SLewanczyk, Dawid 450ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 451ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/{}", chassisIdStr, chassisSubNode); 45295a3ecadSAnthony Wilson 4538fb49dd6SShawn McCarney // Get the list of all sensors for this Chassis element 4548fb49dd6SShawn McCarney std::string sensorPath = *chassisPath + "/all_sensors"; 4556c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 4564e0d8789SEd Tanous sensorPath, [asyncResp, chassisSubNode, sensorTypes, 4574e0d8789SEd Tanous callback = std::forward<Callback>(callback)]( 4588b24275dSEd Tanous const boost::system::error_code& ec2, 4594e0d8789SEd Tanous const dbus::utility::MapperEndPoints& 4604e0d8789SEd Tanous nodeSensorList) mutable { 4618b24275dSEd Tanous if (ec2) 46249c53ac9SJohnathan Mantey { 4638b24275dSEd Tanous if (ec2.value() != EBADR) 46449c53ac9SJohnathan Mantey { 4657f1cc26dSEd Tanous messages::internalError(asyncResp->res); 46649c53ac9SJohnathan Mantey return; 46749c53ac9SJohnathan Mantey } 46849c53ac9SJohnathan Mantey } 469bd79bce8SPatrick Williams const std::shared_ptr<std::set<std::string>> 470bd79bce8SPatrick Williams culledSensorList = 471fe04d49cSNan Zhou std::make_shared<std::set<std::string>>(); 472bd79bce8SPatrick Williams reduceSensorList(asyncResp->res, chassisSubNode, 473bd79bce8SPatrick Williams sensorTypes, &nodeSensorList, 474bd79bce8SPatrick Williams culledSensorList); 475bd79bce8SPatrick Williams BMCWEB_LOG_DEBUG("Finishing with {}", 476bd79bce8SPatrick Williams culledSensorList->size()); 47749c53ac9SJohnathan Mantey callback(culledSensorList); 4781e1e598dSJonathan Doman }); 4797a1dbc48SGeorge Liu }); 48062598e31SEd Tanous BMCWEB_LOG_DEBUG("getChassis exit"); 48108777fb0SLewanczyk, Dawid } 48208777fb0SLewanczyk, Dawid 48308777fb0SLewanczyk, Dawid /** 4841d7c0054SEd Tanous * @brief Builds a json sensor representation of a sensor. 4851d7c0054SEd Tanous * @param sensorName The name of the sensor to be built 4861d7c0054SEd Tanous * @param sensorType The type (temperature, fan_tach, etc) of the sensor to 4871d7c0054SEd Tanous * build 4888ece0e45SEd Tanous * @param chassisSubNode The subnode (thermal, sensor, etc) of the sensor 4891d7c0054SEd Tanous * @param interfacesDict A dictionary of the interfaces and properties of said 4901d7c0054SEd Tanous * interfaces to be built from 4911d7c0054SEd Tanous * @param sensorJson The json object to fill 4921d7c0054SEd Tanous * @param inventoryItem D-Bus inventory item associated with the sensor. Will 4931d7c0054SEd Tanous * be nullptr if no associated inventory item was found. 4941d7c0054SEd Tanous */ 4951d7c0054SEd Tanous inline void objectInterfacesToJson( 4961d7c0054SEd Tanous const std::string& sensorName, const std::string& sensorType, 4970c728b42SJanet Adkins const sensor_utils::ChassisSubNode chassisSubNode, 49880f79a40SMichael Shen const dbus::utility::DBusInterfacesMap& interfacesDict, 4991d7c0054SEd Tanous nlohmann::json& sensorJson, InventoryItem* inventoryItem) 5001d7c0054SEd Tanous { 5011d7c0054SEd Tanous for (const auto& [interface, valuesDict] : interfacesDict) 5021d7c0054SEd Tanous { 503c9563608SJanet Adkins sensor_utils::objectPropertiesToJson( 504c9563608SJanet Adkins sensorName, sensorType, chassisSubNode, valuesDict, sensorJson, 505c9563608SJanet Adkins inventoryItem); 5061d7c0054SEd Tanous } 50762598e31SEd Tanous BMCWEB_LOG_DEBUG("Added sensor {}", sensorName); 5081d7c0054SEd Tanous } 5091d7c0054SEd Tanous 510b5a76932SEd Tanous inline void populateFanRedundancy( 511b5a76932SEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp) 5128bd25ccdSJames Feist { 513e99073f5SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 514e99073f5SGeorge Liu "xyz.openbmc_project.Control.FanRedundancy"}; 515e99073f5SGeorge Liu dbus::utility::getSubTree( 516e99073f5SGeorge Liu "/xyz/openbmc_project/control", 2, interfaces, 517b9d36b47SEd Tanous [sensorsAsyncResp]( 518e99073f5SGeorge Liu const boost::system::error_code& ec, 519b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& resp) { 5208bd25ccdSJames Feist if (ec) 5218bd25ccdSJames Feist { 5228bd25ccdSJames Feist return; // don't have to have this interface 5238bd25ccdSJames Feist } 5246c3e9451SGeorge Liu for (const std::pair<std::string, dbus::utility::MapperServiceMap>& 525e278c18fSEd Tanous pathPair : resp) 5268bd25ccdSJames Feist { 527e278c18fSEd Tanous const std::string& path = pathPair.first; 528bd79bce8SPatrick Williams const dbus::utility::MapperServiceMap& objDict = 529bd79bce8SPatrick Williams pathPair.second; 5308bd25ccdSJames Feist if (objDict.empty()) 5318bd25ccdSJames Feist { 5328bd25ccdSJames Feist continue; // this should be impossible 5338bd25ccdSJames Feist } 5348bd25ccdSJames Feist 5358bd25ccdSJames Feist const std::string& owner = objDict.begin()->first; 5366c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 5376c3e9451SGeorge Liu path + "/chassis", 5386c3e9451SGeorge Liu [path, owner, sensorsAsyncResp]( 5398b24275dSEd Tanous const boost::system::error_code& ec2, 5406c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& endpoints) { 5418b24275dSEd Tanous if (ec2) 5428bd25ccdSJames Feist { 5438bd25ccdSJames Feist return; // if they don't have an association we 5448bd25ccdSJames Feist // can't tell what chassis is 5458bd25ccdSJames Feist } 5463544d2a7SEd Tanous auto found = std::ranges::find_if( 547bd79bce8SPatrick Williams endpoints, 548bd79bce8SPatrick Williams [sensorsAsyncResp](const std::string& entry) { 549bd79bce8SPatrick Williams return entry.find( 550bd79bce8SPatrick Williams sensorsAsyncResp->chassisId) != 5518bd25ccdSJames Feist std::string::npos; 5528bd25ccdSJames Feist }); 5538bd25ccdSJames Feist 5541e1e598dSJonathan Doman if (found == endpoints.end()) 5558bd25ccdSJames Feist { 5568bd25ccdSJames Feist return; 5578bd25ccdSJames Feist } 55886d89ed7SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 55986d89ed7SKrzysztof Grobelny *crow::connections::systemBus, owner, path, 56086d89ed7SKrzysztof Grobelny "xyz.openbmc_project.Control.FanRedundancy", 5618bd25ccdSJames Feist [path, sensorsAsyncResp]( 5628b24275dSEd Tanous const boost::system::error_code& ec3, 56386d89ed7SKrzysztof Grobelny const dbus::utility::DBusPropertiesMap& ret) { 5648b24275dSEd Tanous if (ec3) 5658bd25ccdSJames Feist { 5668bd25ccdSJames Feist return; // don't have to have this 5678bd25ccdSJames Feist // interface 5688bd25ccdSJames Feist } 5698bd25ccdSJames Feist 57086d89ed7SKrzysztof Grobelny const uint8_t* allowedFailures = nullptr; 571bd79bce8SPatrick Williams const std::vector<std::string>* collection = 572bd79bce8SPatrick Williams nullptr; 57386d89ed7SKrzysztof Grobelny const std::string* status = nullptr; 57486d89ed7SKrzysztof Grobelny 575bd79bce8SPatrick Williams const bool success = 576bd79bce8SPatrick Williams sdbusplus::unpackPropertiesNoThrow( 57786d89ed7SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), ret, 578bd79bce8SPatrick Williams "AllowedFailures", allowedFailures, 579bd79bce8SPatrick Williams "Collection", collection, "Status", 580bd79bce8SPatrick Williams status); 58186d89ed7SKrzysztof Grobelny 58286d89ed7SKrzysztof Grobelny if (!success) 58386d89ed7SKrzysztof Grobelny { 58486d89ed7SKrzysztof Grobelny messages::internalError( 58586d89ed7SKrzysztof Grobelny sensorsAsyncResp->asyncResp->res); 58686d89ed7SKrzysztof Grobelny return; 58786d89ed7SKrzysztof Grobelny } 58886d89ed7SKrzysztof Grobelny 589bd79bce8SPatrick Williams if (allowedFailures == nullptr || 590bd79bce8SPatrick Williams collection == nullptr || status == nullptr) 5918bd25ccdSJames Feist { 592bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 593bd79bce8SPatrick Williams "Invalid redundancy interface"); 5948bd25ccdSJames Feist messages::internalError( 5958d1b46d7Szhanghch05 sensorsAsyncResp->asyncResp->res); 5968bd25ccdSJames Feist return; 5978bd25ccdSJames Feist } 5988bd25ccdSJames Feist 599bd79bce8SPatrick Williams sdbusplus::message::object_path objectPath( 600bd79bce8SPatrick Williams path); 60128aa8de5SGeorge Liu std::string name = objectPath.filename(); 60228aa8de5SGeorge Liu if (name.empty()) 6038bd25ccdSJames Feist { 6048bd25ccdSJames Feist // this should be impossible 6058bd25ccdSJames Feist messages::internalError( 6068d1b46d7Szhanghch05 sensorsAsyncResp->asyncResp->res); 6078bd25ccdSJames Feist return; 6088bd25ccdSJames Feist } 60918f8f608SEd Tanous std::ranges::replace(name, '_', ' '); 6108bd25ccdSJames Feist 6118bd25ccdSJames Feist std::string health; 6128bd25ccdSJames Feist 61311ba3979SEd Tanous if (status->ends_with("Full")) 6148bd25ccdSJames Feist { 6158bd25ccdSJames Feist health = "OK"; 6168bd25ccdSJames Feist } 61711ba3979SEd Tanous else if (status->ends_with("Degraded")) 6188bd25ccdSJames Feist { 6198bd25ccdSJames Feist health = "Warning"; 6208bd25ccdSJames Feist } 6218bd25ccdSJames Feist else 6228bd25ccdSJames Feist { 6238bd25ccdSJames Feist health = "Critical"; 6248bd25ccdSJames Feist } 6251476687dSEd Tanous nlohmann::json::array_t redfishCollection; 6268bd25ccdSJames Feist const auto& fanRedfish = 627bd79bce8SPatrick Williams sensorsAsyncResp->asyncResp->res 628bd79bce8SPatrick Williams .jsonValue["Fans"]; 6298bd25ccdSJames Feist for (const std::string& item : *collection) 6308bd25ccdSJames Feist { 631bd79bce8SPatrick Williams sdbusplus::message::object_path itemPath( 632bd79bce8SPatrick Williams item); 6338a592810SEd Tanous std::string itemName = itemPath.filename(); 63428aa8de5SGeorge Liu if (itemName.empty()) 63528aa8de5SGeorge Liu { 63628aa8de5SGeorge Liu continue; 63728aa8de5SGeorge Liu } 6388bd25ccdSJames Feist /* 6398bd25ccdSJames Feist todo(ed): merge patch that fixes the names 6408bd25ccdSJames Feist std::replace(itemName.begin(), 6418bd25ccdSJames Feist itemName.end(), '_', ' ');*/ 6423544d2a7SEd Tanous auto schemaItem = std::ranges::find_if( 643bd79bce8SPatrick Williams fanRedfish, 644bd79bce8SPatrick Williams [itemName](const nlohmann::json& fan) { 6453e35c761SGeorge Liu return fan["Name"] == itemName; 6468bd25ccdSJames Feist }); 6478bd25ccdSJames Feist if (schemaItem != fanRedfish.end()) 6488bd25ccdSJames Feist { 6498a592810SEd Tanous nlohmann::json::object_t collectionId; 6508a592810SEd Tanous collectionId["@odata.id"] = 6511476687dSEd Tanous (*schemaItem)["@odata.id"]; 6521476687dSEd Tanous redfishCollection.emplace_back( 6538a592810SEd Tanous std::move(collectionId)); 6548bd25ccdSJames Feist } 6558bd25ccdSJames Feist else 6568bd25ccdSJames Feist { 657bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 658bd79bce8SPatrick Williams "failed to find fan in schema"); 6598bd25ccdSJames Feist messages::internalError( 6608d1b46d7Szhanghch05 sensorsAsyncResp->asyncResp->res); 6618bd25ccdSJames Feist return; 6628bd25ccdSJames Feist } 6638bd25ccdSJames Feist } 6648bd25ccdSJames Feist 665bd79bce8SPatrick Williams size_t minNumNeeded = 666bd79bce8SPatrick Williams collection->empty() 66726f6976fSEd Tanous ? 0 668bd79bce8SPatrick Williams : collection->size() - *allowedFailures; 669bd79bce8SPatrick Williams nlohmann::json& jResp = 670bd79bce8SPatrick Williams sensorsAsyncResp->asyncResp->res 6718bd25ccdSJames Feist .jsonValue["Redundancy"]; 6721476687dSEd Tanous 6731476687dSEd Tanous nlohmann::json::object_t redundancy; 674bd79bce8SPatrick Williams boost::urls::url url = boost::urls::format( 675bd79bce8SPatrick Williams "/redfish/v1/Chassis/{}/{}", 676ef4c65b7SEd Tanous sensorsAsyncResp->chassisId, 677eddfc437SWilly Tu sensorsAsyncResp->chassisSubNode); 678bd79bce8SPatrick Williams url.set_fragment( 679bd79bce8SPatrick Williams ("/Redundancy"_json_pointer / jResp.size()) 680eddfc437SWilly Tu .to_string()); 681eddfc437SWilly Tu redundancy["@odata.id"] = std::move(url); 682bd79bce8SPatrick Williams redundancy["@odata.type"] = 683bd79bce8SPatrick Williams "#Redundancy.v1_3_2.Redundancy"; 6841476687dSEd Tanous redundancy["MinNumNeeded"] = minNumNeeded; 685bd79bce8SPatrick Williams redundancy["Mode"] = 686bd79bce8SPatrick Williams redundancy::RedundancyType::NPlusM; 6871476687dSEd Tanous redundancy["Name"] = name; 6881476687dSEd Tanous redundancy["RedundancySet"] = redfishCollection; 6891476687dSEd Tanous redundancy["Status"]["Health"] = health; 690bd79bce8SPatrick Williams redundancy["Status"]["State"] = 691bd79bce8SPatrick Williams resource::State::Enabled; 6921476687dSEd Tanous 693b2ba3072SPatrick Williams jResp.emplace_back(std::move(redundancy)); 69486d89ed7SKrzysztof Grobelny }); 6951e1e598dSJonathan Doman }); 6968bd25ccdSJames Feist } 697e99073f5SGeorge Liu }); 6988bd25ccdSJames Feist } 6998bd25ccdSJames Feist 700b5a76932SEd Tanous inline void 70181ce609eSEd Tanous sortJSONResponse(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp) 70249c53ac9SJohnathan Mantey { 7038d1b46d7Szhanghch05 nlohmann::json& response = sensorsAsyncResp->asyncResp->res.jsonValue; 70449c53ac9SJohnathan Mantey std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"}; 7050c728b42SJanet Adkins if (sensorsAsyncResp->chassisSubNode == sensors::powerNodeStr) 70649c53ac9SJohnathan Mantey { 70749c53ac9SJohnathan Mantey sensorHeaders = {"Voltages", "PowerSupplies"}; 70849c53ac9SJohnathan Mantey } 70949c53ac9SJohnathan Mantey for (const std::string& sensorGroup : sensorHeaders) 71049c53ac9SJohnathan Mantey { 71149c53ac9SJohnathan Mantey nlohmann::json::iterator entry = response.find(sensorGroup); 7124e196b9aSEd Tanous if (entry == response.end()) 71349c53ac9SJohnathan Mantey { 7144e196b9aSEd Tanous continue; 7154e196b9aSEd Tanous } 7164e196b9aSEd Tanous nlohmann::json::array_t* arr = 7174e196b9aSEd Tanous entry->get_ptr<nlohmann::json::array_t*>(); 7184e196b9aSEd Tanous if (arr == nullptr) 7194e196b9aSEd Tanous { 7204e196b9aSEd Tanous continue; 7214e196b9aSEd Tanous } 7224e196b9aSEd Tanous json_util::sortJsonArrayByKey(*arr, "Name"); 72349c53ac9SJohnathan Mantey 72449c53ac9SJohnathan Mantey // add the index counts to the end of each entry 72549c53ac9SJohnathan Mantey size_t count = 0; 72649c53ac9SJohnathan Mantey for (nlohmann::json& sensorJson : *entry) 72749c53ac9SJohnathan Mantey { 72849c53ac9SJohnathan Mantey nlohmann::json::iterator odata = sensorJson.find("@odata.id"); 72949c53ac9SJohnathan Mantey if (odata == sensorJson.end()) 73049c53ac9SJohnathan Mantey { 73149c53ac9SJohnathan Mantey continue; 73249c53ac9SJohnathan Mantey } 73349c53ac9SJohnathan Mantey std::string* value = odata->get_ptr<std::string*>(); 73449c53ac9SJohnathan Mantey if (value != nullptr) 73549c53ac9SJohnathan Mantey { 736eddfc437SWilly Tu *value += "/" + std::to_string(count); 7373e35c761SGeorge Liu sensorJson["MemberId"] = std::to_string(count); 73849c53ac9SJohnathan Mantey count++; 73981ce609eSEd Tanous sensorsAsyncResp->updateUri(sensorJson["Name"], *value); 74049c53ac9SJohnathan Mantey } 74149c53ac9SJohnathan Mantey } 74249c53ac9SJohnathan Mantey } 74349c53ac9SJohnathan Mantey } 74449c53ac9SJohnathan Mantey 74508777fb0SLewanczyk, Dawid /** 746adc4f0dbSShawn McCarney * @brief Finds the inventory item with the specified object path. 747adc4f0dbSShawn McCarney * @param inventoryItems D-Bus inventory items associated with sensors. 748adc4f0dbSShawn McCarney * @param invItemObjPath D-Bus object path of inventory item. 749adc4f0dbSShawn McCarney * @return Inventory item within vector, or nullptr if no match found. 7508fb49dd6SShawn McCarney */ 75123a21a1cSEd Tanous inline InventoryItem* findInventoryItem( 752b5a76932SEd Tanous const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems, 753adc4f0dbSShawn McCarney const std::string& invItemObjPath) 7548fb49dd6SShawn McCarney { 755adc4f0dbSShawn McCarney for (InventoryItem& inventoryItem : *inventoryItems) 7568fb49dd6SShawn McCarney { 757adc4f0dbSShawn McCarney if (inventoryItem.objectPath == invItemObjPath) 7588fb49dd6SShawn McCarney { 759adc4f0dbSShawn McCarney return &inventoryItem; 7608fb49dd6SShawn McCarney } 7618fb49dd6SShawn McCarney } 7628fb49dd6SShawn McCarney return nullptr; 7638fb49dd6SShawn McCarney } 7648fb49dd6SShawn McCarney 7658fb49dd6SShawn McCarney /** 766adc4f0dbSShawn McCarney * @brief Finds the inventory item associated with the specified sensor. 767adc4f0dbSShawn McCarney * @param inventoryItems D-Bus inventory items associated with sensors. 768adc4f0dbSShawn McCarney * @param sensorObjPath D-Bus object path of sensor. 769adc4f0dbSShawn McCarney * @return Inventory item within vector, or nullptr if no match found. 7708fb49dd6SShawn McCarney */ 77123a21a1cSEd Tanous inline InventoryItem* findInventoryItemForSensor( 772b5a76932SEd Tanous const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems, 773adc4f0dbSShawn McCarney const std::string& sensorObjPath) 774adc4f0dbSShawn McCarney { 775adc4f0dbSShawn McCarney for (InventoryItem& inventoryItem : *inventoryItems) 776adc4f0dbSShawn McCarney { 777db0d36efSEd Tanous if (inventoryItem.sensors.contains(sensorObjPath)) 778adc4f0dbSShawn McCarney { 779adc4f0dbSShawn McCarney return &inventoryItem; 780adc4f0dbSShawn McCarney } 781adc4f0dbSShawn McCarney } 782adc4f0dbSShawn McCarney return nullptr; 783adc4f0dbSShawn McCarney } 784adc4f0dbSShawn McCarney 785adc4f0dbSShawn McCarney /** 786d500549bSAnthony Wilson * @brief Finds the inventory item associated with the specified led path. 787d500549bSAnthony Wilson * @param inventoryItems D-Bus inventory items associated with sensors. 788d500549bSAnthony Wilson * @param ledObjPath D-Bus object path of led. 789d500549bSAnthony Wilson * @return Inventory item within vector, or nullptr if no match found. 790d500549bSAnthony Wilson */ 791bd79bce8SPatrick Williams inline InventoryItem* findInventoryItemForLed( 792bd79bce8SPatrick Williams std::vector<InventoryItem>& inventoryItems, const std::string& ledObjPath) 793d500549bSAnthony Wilson { 794d500549bSAnthony Wilson for (InventoryItem& inventoryItem : inventoryItems) 795d500549bSAnthony Wilson { 796d500549bSAnthony Wilson if (inventoryItem.ledObjectPath == ledObjPath) 797d500549bSAnthony Wilson { 798d500549bSAnthony Wilson return &inventoryItem; 799d500549bSAnthony Wilson } 800d500549bSAnthony Wilson } 801d500549bSAnthony Wilson return nullptr; 802d500549bSAnthony Wilson } 803d500549bSAnthony Wilson 804d500549bSAnthony Wilson /** 805adc4f0dbSShawn McCarney * @brief Adds inventory item and associated sensor to specified vector. 806adc4f0dbSShawn McCarney * 807adc4f0dbSShawn McCarney * Adds a new InventoryItem to the vector if necessary. Searches for an 808adc4f0dbSShawn McCarney * existing InventoryItem with the specified object path. If not found, one is 809adc4f0dbSShawn McCarney * added to the vector. 810adc4f0dbSShawn McCarney * 811adc4f0dbSShawn McCarney * Next, the specified sensor is added to the set of sensors associated with the 812adc4f0dbSShawn McCarney * InventoryItem. 813adc4f0dbSShawn McCarney * 814adc4f0dbSShawn McCarney * @param inventoryItems D-Bus inventory items associated with sensors. 815adc4f0dbSShawn McCarney * @param invItemObjPath D-Bus object path of inventory item. 816adc4f0dbSShawn McCarney * @param sensorObjPath D-Bus object path of sensor 817adc4f0dbSShawn McCarney */ 818b5a76932SEd Tanous inline void addInventoryItem( 819b5a76932SEd Tanous const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems, 820b5a76932SEd Tanous const std::string& invItemObjPath, const std::string& sensorObjPath) 821adc4f0dbSShawn McCarney { 822adc4f0dbSShawn McCarney // Look for inventory item in vector 823bd79bce8SPatrick Williams InventoryItem* inventoryItem = 824bd79bce8SPatrick Williams findInventoryItem(inventoryItems, invItemObjPath); 825adc4f0dbSShawn McCarney 826adc4f0dbSShawn McCarney // If inventory item doesn't exist in vector, add it 827adc4f0dbSShawn McCarney if (inventoryItem == nullptr) 828adc4f0dbSShawn McCarney { 829adc4f0dbSShawn McCarney inventoryItems->emplace_back(invItemObjPath); 830adc4f0dbSShawn McCarney inventoryItem = &(inventoryItems->back()); 831adc4f0dbSShawn McCarney } 832adc4f0dbSShawn McCarney 833adc4f0dbSShawn McCarney // Add sensor to set of sensors associated with inventory item 834adc4f0dbSShawn McCarney inventoryItem->sensors.emplace(sensorObjPath); 835adc4f0dbSShawn McCarney } 836adc4f0dbSShawn McCarney 837adc4f0dbSShawn McCarney /** 838adc4f0dbSShawn McCarney * @brief Stores D-Bus data in the specified inventory item. 839adc4f0dbSShawn McCarney * 840adc4f0dbSShawn McCarney * Finds D-Bus data in the specified map of interfaces. Stores the data in the 841adc4f0dbSShawn McCarney * specified InventoryItem. 842adc4f0dbSShawn McCarney * 843adc4f0dbSShawn McCarney * This data is later used to provide sensor property values in the JSON 844adc4f0dbSShawn McCarney * response. 845adc4f0dbSShawn McCarney * 846adc4f0dbSShawn McCarney * @param inventoryItem Inventory item where data will be stored. 847adc4f0dbSShawn McCarney * @param interfacesDict Map containing D-Bus interfaces and their properties 848adc4f0dbSShawn McCarney * for the specified inventory item. 849adc4f0dbSShawn McCarney */ 85023a21a1cSEd Tanous inline void storeInventoryItemData( 851adc4f0dbSShawn McCarney InventoryItem& inventoryItem, 85280f79a40SMichael Shen const dbus::utility::DBusInterfacesMap& interfacesDict) 8538fb49dd6SShawn McCarney { 854adc4f0dbSShawn McCarney // Get properties from Inventory.Item interface 855711ac7a9SEd Tanous 8569eb808c1SEd Tanous for (const auto& [interface, values] : interfacesDict) 8578fb49dd6SShawn McCarney { 858711ac7a9SEd Tanous if (interface == "xyz.openbmc_project.Inventory.Item") 8598fb49dd6SShawn McCarney { 8609eb808c1SEd Tanous for (const auto& [name, dbusValue] : values) 861711ac7a9SEd Tanous { 862711ac7a9SEd Tanous if (name == "Present") 863711ac7a9SEd Tanous { 864711ac7a9SEd Tanous const bool* value = std::get_if<bool>(&dbusValue); 865adc4f0dbSShawn McCarney if (value != nullptr) 8668fb49dd6SShawn McCarney { 867adc4f0dbSShawn McCarney inventoryItem.isPresent = *value; 8688fb49dd6SShawn McCarney } 8698fb49dd6SShawn McCarney } 8708fb49dd6SShawn McCarney } 871711ac7a9SEd Tanous } 872adc4f0dbSShawn McCarney // Check if Inventory.Item.PowerSupply interface is present 873711ac7a9SEd Tanous 874711ac7a9SEd Tanous if (interface == "xyz.openbmc_project.Inventory.Item.PowerSupply") 8758fb49dd6SShawn McCarney { 876adc4f0dbSShawn McCarney inventoryItem.isPowerSupply = true; 8778fb49dd6SShawn McCarney } 878adc4f0dbSShawn McCarney 879adc4f0dbSShawn McCarney // Get properties from Inventory.Decorator.Asset interface 880711ac7a9SEd Tanous if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset") 881adc4f0dbSShawn McCarney { 8829eb808c1SEd Tanous for (const auto& [name, dbusValue] : values) 883711ac7a9SEd Tanous { 884711ac7a9SEd Tanous if (name == "Manufacturer") 885adc4f0dbSShawn McCarney { 886adc4f0dbSShawn McCarney const std::string* value = 887711ac7a9SEd Tanous std::get_if<std::string>(&dbusValue); 888adc4f0dbSShawn McCarney if (value != nullptr) 889adc4f0dbSShawn McCarney { 890adc4f0dbSShawn McCarney inventoryItem.manufacturer = *value; 891adc4f0dbSShawn McCarney } 892adc4f0dbSShawn McCarney } 893711ac7a9SEd Tanous if (name == "Model") 894adc4f0dbSShawn McCarney { 895adc4f0dbSShawn McCarney const std::string* value = 896711ac7a9SEd Tanous std::get_if<std::string>(&dbusValue); 897adc4f0dbSShawn McCarney if (value != nullptr) 898adc4f0dbSShawn McCarney { 899adc4f0dbSShawn McCarney inventoryItem.model = *value; 900adc4f0dbSShawn McCarney } 901adc4f0dbSShawn McCarney } 902711ac7a9SEd Tanous if (name == "SerialNumber") 903adc4f0dbSShawn McCarney { 904adc4f0dbSShawn McCarney const std::string* value = 905711ac7a9SEd Tanous std::get_if<std::string>(&dbusValue); 906adc4f0dbSShawn McCarney if (value != nullptr) 907adc4f0dbSShawn McCarney { 908adc4f0dbSShawn McCarney inventoryItem.serialNumber = *value; 909adc4f0dbSShawn McCarney } 910adc4f0dbSShawn McCarney } 911711ac7a9SEd Tanous if (name == "PartNumber") 912711ac7a9SEd Tanous { 913711ac7a9SEd Tanous const std::string* value = 914711ac7a9SEd Tanous std::get_if<std::string>(&dbusValue); 915711ac7a9SEd Tanous if (value != nullptr) 916711ac7a9SEd Tanous { 917711ac7a9SEd Tanous inventoryItem.partNumber = *value; 918711ac7a9SEd Tanous } 919711ac7a9SEd Tanous } 920711ac7a9SEd Tanous } 921adc4f0dbSShawn McCarney } 922adc4f0dbSShawn McCarney 923711ac7a9SEd Tanous if (interface == 924711ac7a9SEd Tanous "xyz.openbmc_project.State.Decorator.OperationalStatus") 925adc4f0dbSShawn McCarney { 9269eb808c1SEd Tanous for (const auto& [name, dbusValue] : values) 927adc4f0dbSShawn McCarney { 928711ac7a9SEd Tanous if (name == "Functional") 929711ac7a9SEd Tanous { 930711ac7a9SEd Tanous const bool* value = std::get_if<bool>(&dbusValue); 931adc4f0dbSShawn McCarney if (value != nullptr) 932adc4f0dbSShawn McCarney { 933adc4f0dbSShawn McCarney inventoryItem.isFunctional = *value; 9348fb49dd6SShawn McCarney } 9358fb49dd6SShawn McCarney } 9368fb49dd6SShawn McCarney } 9378fb49dd6SShawn McCarney } 938711ac7a9SEd Tanous } 939711ac7a9SEd Tanous } 9408fb49dd6SShawn McCarney 9418fb49dd6SShawn McCarney /** 942adc4f0dbSShawn McCarney * @brief Gets D-Bus data for inventory items associated with sensors. 9438fb49dd6SShawn McCarney * 944adc4f0dbSShawn McCarney * Uses the specified connections (services) to obtain D-Bus data for inventory 945adc4f0dbSShawn McCarney * items associated with sensors. Stores the resulting data in the 946adc4f0dbSShawn McCarney * inventoryItems vector. 9478fb49dd6SShawn McCarney * 948adc4f0dbSShawn McCarney * This data is later used to provide sensor property values in the JSON 949adc4f0dbSShawn McCarney * response. 950adc4f0dbSShawn McCarney * 951adc4f0dbSShawn McCarney * Finds the inventory item data asynchronously. Invokes callback when data has 952adc4f0dbSShawn McCarney * been obtained. 953adc4f0dbSShawn McCarney * 954adc4f0dbSShawn McCarney * The callback must have the following signature: 955adc4f0dbSShawn McCarney * @code 956d500549bSAnthony Wilson * callback(void) 957adc4f0dbSShawn McCarney * @endcode 958adc4f0dbSShawn McCarney * 959adc4f0dbSShawn McCarney * This function is called recursively, obtaining data asynchronously from one 960adc4f0dbSShawn McCarney * connection in each call. This ensures the callback is not invoked until the 961adc4f0dbSShawn McCarney * last asynchronous function has completed. 9628fb49dd6SShawn McCarney * 9638fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 964adc4f0dbSShawn McCarney * @param inventoryItems D-Bus inventory items associated with sensors. 965adc4f0dbSShawn McCarney * @param invConnections Connections that provide data for the inventory items. 9668fb49dd6SShawn McCarney * implements ObjectManager. 967adc4f0dbSShawn McCarney * @param callback Callback to invoke when inventory data has been obtained. 968adc4f0dbSShawn McCarney * @param invConnectionsIndex Current index in invConnections. Only specified 969adc4f0dbSShawn McCarney * in recursive calls to this function. 9708fb49dd6SShawn McCarney */ 971adc4f0dbSShawn McCarney template <typename Callback> 9724ff0f1f4SEd Tanous void getInventoryItemsData( 9738fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 974adc4f0dbSShawn McCarney std::shared_ptr<std::vector<InventoryItem>> inventoryItems, 975d0090733SEd Tanous std::shared_ptr<std::set<std::string>> invConnections, Callback&& callback, 976d0090733SEd Tanous size_t invConnectionsIndex = 0) 9778fb49dd6SShawn McCarney { 97862598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsData enter"); 9798fb49dd6SShawn McCarney 980adc4f0dbSShawn McCarney // If no more connections left, call callback 981adc4f0dbSShawn McCarney if (invConnectionsIndex >= invConnections->size()) 9828fb49dd6SShawn McCarney { 983d500549bSAnthony Wilson callback(); 98462598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsData exit"); 985adc4f0dbSShawn McCarney return; 986adc4f0dbSShawn McCarney } 987adc4f0dbSShawn McCarney 988adc4f0dbSShawn McCarney // Get inventory item data from current connection 989fe04d49cSNan Zhou auto it = invConnections->begin(); 990fe04d49cSNan Zhou std::advance(it, invConnectionsIndex); 991adc4f0dbSShawn McCarney if (it != invConnections->end()) 992adc4f0dbSShawn McCarney { 993adc4f0dbSShawn McCarney const std::string& invConnection = *it; 994adc4f0dbSShawn McCarney 9955eb468daSGeorge Liu // Get all object paths and their interfaces for current connection 9965eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/inventory"); 9975eb468daSGeorge Liu dbus::utility::getManagedObjects( 9985eb468daSGeorge Liu invConnection, path, 9995eb468daSGeorge Liu [sensorsAsyncResp, inventoryItems, invConnections, 10008cb2c024SEd Tanous callback = std::forward<Callback>(callback), invConnectionsIndex]( 10015e7e2dc5SEd Tanous const boost::system::error_code& ec, 10024e0d8789SEd Tanous const dbus::utility::ManagedObjectType& resp) mutable { 100362598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler enter"); 10048fb49dd6SShawn McCarney if (ec) 10058fb49dd6SShawn McCarney { 100662598e31SEd Tanous BMCWEB_LOG_ERROR( 100762598e31SEd Tanous "getInventoryItemsData respHandler DBus error {}", ec); 10088d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 10098fb49dd6SShawn McCarney return; 10108fb49dd6SShawn McCarney } 10118fb49dd6SShawn McCarney 10128fb49dd6SShawn McCarney // Loop through returned object paths 10138fb49dd6SShawn McCarney for (const auto& objDictEntry : resp) 10148fb49dd6SShawn McCarney { 10158fb49dd6SShawn McCarney const std::string& objPath = 10168fb49dd6SShawn McCarney static_cast<const std::string&>(objDictEntry.first); 10178fb49dd6SShawn McCarney 1018bd79bce8SPatrick Williams // If this object path is one of the specified inventory 1019bd79bce8SPatrick Williams // items 1020bd79bce8SPatrick Williams InventoryItem* inventoryItem = 1021bd79bce8SPatrick Williams findInventoryItem(inventoryItems, objPath); 1022adc4f0dbSShawn McCarney if (inventoryItem != nullptr) 10238fb49dd6SShawn McCarney { 1024adc4f0dbSShawn McCarney // Store inventory data in InventoryItem 1025bd79bce8SPatrick Williams storeInventoryItemData(*inventoryItem, 1026bd79bce8SPatrick Williams objDictEntry.second); 10278fb49dd6SShawn McCarney } 10288fb49dd6SShawn McCarney } 10298fb49dd6SShawn McCarney 1030adc4f0dbSShawn McCarney // Recurse to get inventory item data from next connection 1031adc4f0dbSShawn McCarney getInventoryItemsData(sensorsAsyncResp, inventoryItems, 1032d0090733SEd Tanous invConnections, std::move(callback), 1033d0090733SEd Tanous invConnectionsIndex + 1); 1034adc4f0dbSShawn McCarney 103562598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler exit"); 10365eb468daSGeorge Liu }); 10378fb49dd6SShawn McCarney } 10388fb49dd6SShawn McCarney 103962598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsData exit"); 10408fb49dd6SShawn McCarney } 10418fb49dd6SShawn McCarney 10428fb49dd6SShawn McCarney /** 1043adc4f0dbSShawn McCarney * @brief Gets connections that provide D-Bus data for inventory items. 10448fb49dd6SShawn McCarney * 1045adc4f0dbSShawn McCarney * Gets the D-Bus connections (services) that provide data for the inventory 1046adc4f0dbSShawn McCarney * items that are associated with sensors. 10478fb49dd6SShawn McCarney * 10488fb49dd6SShawn McCarney * Finds the connections asynchronously. Invokes callback when information has 10498fb49dd6SShawn McCarney * been obtained. 10508fb49dd6SShawn McCarney * 10518fb49dd6SShawn McCarney * The callback must have the following signature: 10528fb49dd6SShawn McCarney * @code 1053fe04d49cSNan Zhou * callback(std::shared_ptr<std::set<std::string>> invConnections) 10548fb49dd6SShawn McCarney * @endcode 10558fb49dd6SShawn McCarney * 10568fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 1057adc4f0dbSShawn McCarney * @param inventoryItems D-Bus inventory items associated with sensors. 10588fb49dd6SShawn McCarney * @param callback Callback to invoke when connections have been obtained. 10598fb49dd6SShawn McCarney */ 10608fb49dd6SShawn McCarney template <typename Callback> 10614ff0f1f4SEd Tanous void getInventoryItemsConnections( 1062b5a76932SEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp, 1063b5a76932SEd Tanous const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems, 10648fb49dd6SShawn McCarney Callback&& callback) 10658fb49dd6SShawn McCarney { 106662598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsConnections enter"); 10678fb49dd6SShawn McCarney 10688fb49dd6SShawn McCarney const std::string path = "/xyz/openbmc_project/inventory"; 1069e99073f5SGeorge Liu constexpr std::array<std::string_view, 4> interfaces = { 10708fb49dd6SShawn McCarney "xyz.openbmc_project.Inventory.Item", 1071adc4f0dbSShawn McCarney "xyz.openbmc_project.Inventory.Item.PowerSupply", 1072adc4f0dbSShawn McCarney "xyz.openbmc_project.Inventory.Decorator.Asset", 10738fb49dd6SShawn McCarney "xyz.openbmc_project.State.Decorator.OperationalStatus"}; 10748fb49dd6SShawn McCarney 1075e99073f5SGeorge Liu // Make call to ObjectMapper to find all inventory items 1076e99073f5SGeorge Liu dbus::utility::getSubTree( 1077e99073f5SGeorge Liu path, 0, interfaces, 10788cb2c024SEd Tanous [callback = std::forward<Callback>(callback), sensorsAsyncResp, 1079002d39b4SEd Tanous inventoryItems]( 1080e99073f5SGeorge Liu const boost::system::error_code& ec, 10814e0d8789SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) mutable { 1082e99073f5SGeorge Liu // Response handler for parsing output from GetSubTree 108362598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler enter"); 10848fb49dd6SShawn McCarney if (ec) 10858fb49dd6SShawn McCarney { 10868d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 108762598e31SEd Tanous BMCWEB_LOG_ERROR( 1088bd79bce8SPatrick Williams "getInventoryItemsConnections respHandler DBus error {}", 1089bd79bce8SPatrick Williams ec); 10908fb49dd6SShawn McCarney return; 10918fb49dd6SShawn McCarney } 10928fb49dd6SShawn McCarney 10938fb49dd6SShawn McCarney // Make unique list of connections for desired inventory items 1094fe04d49cSNan Zhou std::shared_ptr<std::set<std::string>> invConnections = 1095fe04d49cSNan Zhou std::make_shared<std::set<std::string>>(); 10968fb49dd6SShawn McCarney 10978fb49dd6SShawn McCarney // Loop through objects from GetSubTree 1098bd79bce8SPatrick Williams for (const std::pair<std::string, 1099bd79bce8SPatrick Williams std::vector<std::pair< 1100bd79bce8SPatrick Williams std::string, std::vector<std::string>>>>& 11018fb49dd6SShawn McCarney object : subtree) 11028fb49dd6SShawn McCarney { 1103adc4f0dbSShawn McCarney // Check if object path is one of the specified inventory items 11048fb49dd6SShawn McCarney const std::string& objPath = object.first; 1105adc4f0dbSShawn McCarney if (findInventoryItem(inventoryItems, objPath) != nullptr) 11068fb49dd6SShawn McCarney { 11078fb49dd6SShawn McCarney // Store all connections to inventory item 11088fb49dd6SShawn McCarney for (const std::pair<std::string, std::vector<std::string>>& 11098fb49dd6SShawn McCarney objData : object.second) 11108fb49dd6SShawn McCarney { 11118fb49dd6SShawn McCarney const std::string& invConnection = objData.first; 11128fb49dd6SShawn McCarney invConnections->insert(invConnection); 11138fb49dd6SShawn McCarney } 11148fb49dd6SShawn McCarney } 11158fb49dd6SShawn McCarney } 1116d500549bSAnthony Wilson 11178fb49dd6SShawn McCarney callback(invConnections); 111862598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler exit"); 1119e99073f5SGeorge Liu }); 112062598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsConnections exit"); 11218fb49dd6SShawn McCarney } 11228fb49dd6SShawn McCarney 11238fb49dd6SShawn McCarney /** 1124adc4f0dbSShawn McCarney * @brief Gets associations from sensors to inventory items. 11258fb49dd6SShawn McCarney * 11268fb49dd6SShawn McCarney * Looks for ObjectMapper associations from the specified sensors to related 1127d500549bSAnthony Wilson * inventory items. Then finds the associations from those inventory items to 1128d500549bSAnthony Wilson * their LEDs, if any. 11298fb49dd6SShawn McCarney * 11308fb49dd6SShawn McCarney * Finds the inventory items asynchronously. Invokes callback when information 11318fb49dd6SShawn McCarney * has been obtained. 11328fb49dd6SShawn McCarney * 11338fb49dd6SShawn McCarney * The callback must have the following signature: 11348fb49dd6SShawn McCarney * @code 1135adc4f0dbSShawn McCarney * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems) 11368fb49dd6SShawn McCarney * @endcode 11378fb49dd6SShawn McCarney * 11388fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 11398fb49dd6SShawn McCarney * @param sensorNames All sensors within the current chassis. 11408fb49dd6SShawn McCarney * implements ObjectManager. 11418fb49dd6SShawn McCarney * @param callback Callback to invoke when inventory items have been obtained. 11428fb49dd6SShawn McCarney */ 11438fb49dd6SShawn McCarney template <typename Callback> 11444ff0f1f4SEd Tanous void getInventoryItemAssociations( 1145b5a76932SEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp, 1146fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& sensorNames, 11478fb49dd6SShawn McCarney Callback&& callback) 11488fb49dd6SShawn McCarney { 114962598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemAssociations enter"); 11508fb49dd6SShawn McCarney 11515eb468daSGeorge Liu // Call GetManagedObjects on the ObjectMapper to get all associations 11525eb468daSGeorge Liu sdbusplus::message::object_path path("/"); 11535eb468daSGeorge Liu dbus::utility::getManagedObjects( 11545eb468daSGeorge Liu "xyz.openbmc_project.ObjectMapper", path, 11558cb2c024SEd Tanous [callback = std::forward<Callback>(callback), sensorsAsyncResp, 11565e7e2dc5SEd Tanous sensorNames](const boost::system::error_code& ec, 11574e0d8789SEd Tanous const dbus::utility::ManagedObjectType& resp) mutable { 115862598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler enter"); 11598fb49dd6SShawn McCarney if (ec) 11608fb49dd6SShawn McCarney { 116162598e31SEd Tanous BMCWEB_LOG_ERROR( 1162bd79bce8SPatrick Williams "getInventoryItemAssociations respHandler DBus error {}", 1163bd79bce8SPatrick Williams ec); 11648d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 11658fb49dd6SShawn McCarney return; 11668fb49dd6SShawn McCarney } 11678fb49dd6SShawn McCarney 1168adc4f0dbSShawn McCarney // Create vector to hold list of inventory items 1169adc4f0dbSShawn McCarney std::shared_ptr<std::vector<InventoryItem>> inventoryItems = 1170adc4f0dbSShawn McCarney std::make_shared<std::vector<InventoryItem>>(); 1171adc4f0dbSShawn McCarney 11728fb49dd6SShawn McCarney // Loop through returned object paths 11738fb49dd6SShawn McCarney std::string sensorAssocPath; 11748fb49dd6SShawn McCarney sensorAssocPath.reserve(128); // avoid memory allocations 11758fb49dd6SShawn McCarney for (const auto& objDictEntry : resp) 11768fb49dd6SShawn McCarney { 11778fb49dd6SShawn McCarney const std::string& objPath = 11788fb49dd6SShawn McCarney static_cast<const std::string&>(objDictEntry.first); 11798fb49dd6SShawn McCarney 1180bd79bce8SPatrick Williams // If path is inventory association for one of the specified 1181bd79bce8SPatrick Williams // sensors 11828fb49dd6SShawn McCarney for (const std::string& sensorName : *sensorNames) 11838fb49dd6SShawn McCarney { 11848fb49dd6SShawn McCarney sensorAssocPath = sensorName; 11858fb49dd6SShawn McCarney sensorAssocPath += "/inventory"; 11868fb49dd6SShawn McCarney if (objPath == sensorAssocPath) 11878fb49dd6SShawn McCarney { 11888fb49dd6SShawn McCarney // Get Association interface for object path 1189bd79bce8SPatrick Williams for (const auto& [interface, values] : 1190bd79bce8SPatrick Williams objDictEntry.second) 11918fb49dd6SShawn McCarney { 1192711ac7a9SEd Tanous if (interface == "xyz.openbmc_project.Association") 1193711ac7a9SEd Tanous { 1194711ac7a9SEd Tanous for (const auto& [valueName, value] : values) 1195711ac7a9SEd Tanous { 1196711ac7a9SEd Tanous if (valueName == "endpoints") 11978fb49dd6SShawn McCarney { 1198bd79bce8SPatrick Williams const std::vector<std::string>* 1199bd79bce8SPatrick Williams endpoints = std::get_if< 1200bd79bce8SPatrick Williams std::vector<std::string>>( 1201711ac7a9SEd Tanous &value); 1202711ac7a9SEd Tanous if ((endpoints != nullptr) && 1203711ac7a9SEd Tanous !endpoints->empty()) 12048fb49dd6SShawn McCarney { 1205adc4f0dbSShawn McCarney // Add inventory item to vector 1206adc4f0dbSShawn McCarney const std::string& invItemPath = 1207adc4f0dbSShawn McCarney endpoints->front(); 1208711ac7a9SEd Tanous addInventoryItem(inventoryItems, 1209711ac7a9SEd Tanous invItemPath, 1210adc4f0dbSShawn McCarney sensorName); 12118fb49dd6SShawn McCarney } 12128fb49dd6SShawn McCarney } 12138fb49dd6SShawn McCarney } 1214711ac7a9SEd Tanous } 1215711ac7a9SEd Tanous } 12168fb49dd6SShawn McCarney break; 12178fb49dd6SShawn McCarney } 12188fb49dd6SShawn McCarney } 12198fb49dd6SShawn McCarney } 12208fb49dd6SShawn McCarney 1221d500549bSAnthony Wilson // Now loop through the returned object paths again, this time to 1222d500549bSAnthony Wilson // find the leds associated with the inventory items we just found 1223d500549bSAnthony Wilson std::string inventoryAssocPath; 1224d500549bSAnthony Wilson inventoryAssocPath.reserve(128); // avoid memory allocations 1225d500549bSAnthony Wilson for (const auto& objDictEntry : resp) 1226d500549bSAnthony Wilson { 1227d500549bSAnthony Wilson const std::string& objPath = 1228d500549bSAnthony Wilson static_cast<const std::string&>(objDictEntry.first); 1229d500549bSAnthony Wilson 1230d500549bSAnthony Wilson for (InventoryItem& inventoryItem : *inventoryItems) 1231d500549bSAnthony Wilson { 1232d500549bSAnthony Wilson inventoryAssocPath = inventoryItem.objectPath; 1233d500549bSAnthony Wilson inventoryAssocPath += "/leds"; 1234d500549bSAnthony Wilson if (objPath == inventoryAssocPath) 1235d500549bSAnthony Wilson { 1236bd79bce8SPatrick Williams for (const auto& [interface, values] : 1237bd79bce8SPatrick Williams objDictEntry.second) 1238d500549bSAnthony Wilson { 1239711ac7a9SEd Tanous if (interface == "xyz.openbmc_project.Association") 1240711ac7a9SEd Tanous { 1241711ac7a9SEd Tanous for (const auto& [valueName, value] : values) 1242711ac7a9SEd Tanous { 1243711ac7a9SEd Tanous if (valueName == "endpoints") 1244d500549bSAnthony Wilson { 1245bd79bce8SPatrick Williams const std::vector<std::string>* 1246bd79bce8SPatrick Williams endpoints = std::get_if< 1247bd79bce8SPatrick Williams std::vector<std::string>>( 1248711ac7a9SEd Tanous &value); 1249711ac7a9SEd Tanous if ((endpoints != nullptr) && 1250711ac7a9SEd Tanous !endpoints->empty()) 1251d500549bSAnthony Wilson { 1252711ac7a9SEd Tanous // Add inventory item to vector 1253d500549bSAnthony Wilson // Store LED path in inventory item 1254711ac7a9SEd Tanous const std::string& ledPath = 1255711ac7a9SEd Tanous endpoints->front(); 1256bd79bce8SPatrick Williams inventoryItem.ledObjectPath = 1257bd79bce8SPatrick Williams ledPath; 1258d500549bSAnthony Wilson } 1259d500549bSAnthony Wilson } 1260d500549bSAnthony Wilson } 1261711ac7a9SEd Tanous } 1262711ac7a9SEd Tanous } 1263711ac7a9SEd Tanous 1264d500549bSAnthony Wilson break; 1265d500549bSAnthony Wilson } 1266d500549bSAnthony Wilson } 1267d500549bSAnthony Wilson } 1268adc4f0dbSShawn McCarney callback(inventoryItems); 126962598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler exit"); 12705eb468daSGeorge Liu }); 12718fb49dd6SShawn McCarney 127262598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemAssociations exit"); 12738fb49dd6SShawn McCarney } 12748fb49dd6SShawn McCarney 12758fb49dd6SShawn McCarney /** 1276d500549bSAnthony Wilson * @brief Gets D-Bus data for inventory item leds associated with sensors. 1277d500549bSAnthony Wilson * 1278d500549bSAnthony Wilson * Uses the specified connections (services) to obtain D-Bus data for inventory 1279d500549bSAnthony Wilson * item leds associated with sensors. Stores the resulting data in the 1280d500549bSAnthony Wilson * inventoryItems vector. 1281d500549bSAnthony Wilson * 1282d500549bSAnthony Wilson * This data is later used to provide sensor property values in the JSON 1283d500549bSAnthony Wilson * response. 1284d500549bSAnthony Wilson * 1285d500549bSAnthony Wilson * Finds the inventory item led data asynchronously. Invokes callback when data 1286d500549bSAnthony Wilson * has been obtained. 1287d500549bSAnthony Wilson * 1288d500549bSAnthony Wilson * The callback must have the following signature: 1289d500549bSAnthony Wilson * @code 129042cbe538SGunnar Mills * callback() 1291d500549bSAnthony Wilson * @endcode 1292d500549bSAnthony Wilson * 1293d500549bSAnthony Wilson * This function is called recursively, obtaining data asynchronously from one 1294d500549bSAnthony Wilson * connection in each call. This ensures the callback is not invoked until the 1295d500549bSAnthony Wilson * last asynchronous function has completed. 1296d500549bSAnthony Wilson * 1297d500549bSAnthony Wilson * @param sensorsAsyncResp Pointer to object holding response data. 1298d500549bSAnthony Wilson * @param inventoryItems D-Bus inventory items associated with sensors. 1299d500549bSAnthony Wilson * @param ledConnections Connections that provide data for the inventory leds. 1300d500549bSAnthony Wilson * @param callback Callback to invoke when inventory data has been obtained. 1301d500549bSAnthony Wilson * @param ledConnectionsIndex Current index in ledConnections. Only specified 1302d500549bSAnthony Wilson * in recursive calls to this function. 1303d500549bSAnthony Wilson */ 1304d500549bSAnthony Wilson template <typename Callback> 1305d500549bSAnthony Wilson void getInventoryLedData( 1306d500549bSAnthony Wilson std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 1307d500549bSAnthony Wilson std::shared_ptr<std::vector<InventoryItem>> inventoryItems, 1308fe04d49cSNan Zhou std::shared_ptr<std::map<std::string, std::string>> ledConnections, 1309d500549bSAnthony Wilson Callback&& callback, size_t ledConnectionsIndex = 0) 1310d500549bSAnthony Wilson { 131162598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryLedData enter"); 1312d500549bSAnthony Wilson 1313d500549bSAnthony Wilson // If no more connections left, call callback 1314d500549bSAnthony Wilson if (ledConnectionsIndex >= ledConnections->size()) 1315d500549bSAnthony Wilson { 131642cbe538SGunnar Mills callback(); 131762598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryLedData exit"); 1318d500549bSAnthony Wilson return; 1319d500549bSAnthony Wilson } 1320d500549bSAnthony Wilson 1321d500549bSAnthony Wilson // Get inventory item data from current connection 1322fe04d49cSNan Zhou auto it = ledConnections->begin(); 1323fe04d49cSNan Zhou std::advance(it, ledConnectionsIndex); 1324d500549bSAnthony Wilson if (it != ledConnections->end()) 1325d500549bSAnthony Wilson { 1326d500549bSAnthony Wilson const std::string& ledPath = (*it).first; 1327d500549bSAnthony Wilson const std::string& ledConnection = (*it).second; 1328d500549bSAnthony Wilson // Response handler for Get State property 13291e1e598dSJonathan Doman auto respHandler = 13301e1e598dSJonathan Doman [sensorsAsyncResp, inventoryItems, ledConnections, ledPath, 13314e0d8789SEd Tanous callback = std::forward<Callback>(callback), 13324e0d8789SEd Tanous ledConnectionsIndex](const boost::system::error_code& ec, 13334e0d8789SEd Tanous const std::string& state) mutable { 133462598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryLedData respHandler enter"); 1335d500549bSAnthony Wilson if (ec) 1336d500549bSAnthony Wilson { 133762598e31SEd Tanous BMCWEB_LOG_ERROR( 133862598e31SEd Tanous "getInventoryLedData respHandler DBus error {}", ec); 13398d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 1340d500549bSAnthony Wilson return; 1341d500549bSAnthony Wilson } 1342d500549bSAnthony Wilson 134362598e31SEd Tanous BMCWEB_LOG_DEBUG("Led state: {}", state); 1344d500549bSAnthony Wilson // Find inventory item with this LED object path 1345d500549bSAnthony Wilson InventoryItem* inventoryItem = 1346d500549bSAnthony Wilson findInventoryItemForLed(*inventoryItems, ledPath); 1347d500549bSAnthony Wilson if (inventoryItem != nullptr) 1348d500549bSAnthony Wilson { 1349d500549bSAnthony Wilson // Store LED state in InventoryItem 135011ba3979SEd Tanous if (state.ends_with("On")) 1351d500549bSAnthony Wilson { 1352c9563608SJanet Adkins inventoryItem->ledState = sensor_utils::LedState::ON; 1353d500549bSAnthony Wilson } 135411ba3979SEd Tanous else if (state.ends_with("Blink")) 1355d500549bSAnthony Wilson { 1356c9563608SJanet Adkins inventoryItem->ledState = sensor_utils::LedState::BLINK; 1357d500549bSAnthony Wilson } 135811ba3979SEd Tanous else if (state.ends_with("Off")) 1359d500549bSAnthony Wilson { 1360c9563608SJanet Adkins inventoryItem->ledState = sensor_utils::LedState::OFF; 1361d500549bSAnthony Wilson } 1362d500549bSAnthony Wilson else 1363d500549bSAnthony Wilson { 1364c9563608SJanet Adkins inventoryItem->ledState = 1365c9563608SJanet Adkins sensor_utils::LedState::UNKNOWN; 1366d500549bSAnthony Wilson } 1367d500549bSAnthony Wilson } 1368d500549bSAnthony Wilson 1369d500549bSAnthony Wilson // Recurse to get LED data from next connection 1370d500549bSAnthony Wilson getInventoryLedData(sensorsAsyncResp, inventoryItems, 1371d500549bSAnthony Wilson ledConnections, std::move(callback), 1372d500549bSAnthony Wilson ledConnectionsIndex + 1); 1373d500549bSAnthony Wilson 137462598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryLedData respHandler exit"); 1375d500549bSAnthony Wilson }; 1376d500549bSAnthony Wilson 1377d500549bSAnthony Wilson // Get the State property for the current LED 13781e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 13791e1e598dSJonathan Doman *crow::connections::systemBus, ledConnection, ledPath, 13801e1e598dSJonathan Doman "xyz.openbmc_project.Led.Physical", "State", 13811e1e598dSJonathan Doman std::move(respHandler)); 1382d500549bSAnthony Wilson } 1383d500549bSAnthony Wilson 138462598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryLedData exit"); 1385d500549bSAnthony Wilson } 1386d500549bSAnthony Wilson 1387d500549bSAnthony Wilson /** 1388d500549bSAnthony Wilson * @brief Gets LED data for LEDs associated with given inventory items. 1389d500549bSAnthony Wilson * 1390d500549bSAnthony Wilson * Gets the D-Bus connections (services) that provide LED data for the LEDs 1391d500549bSAnthony Wilson * associated with the specified inventory items. Then gets the LED data from 1392d500549bSAnthony Wilson * each connection and stores it in the inventory item. 1393d500549bSAnthony Wilson * 1394d500549bSAnthony Wilson * This data is later used to provide sensor property values in the JSON 1395d500549bSAnthony Wilson * response. 1396d500549bSAnthony Wilson * 1397d500549bSAnthony Wilson * Finds the LED data asynchronously. Invokes callback when information has 1398d500549bSAnthony Wilson * been obtained. 1399d500549bSAnthony Wilson * 1400d500549bSAnthony Wilson * The callback must have the following signature: 1401d500549bSAnthony Wilson * @code 140242cbe538SGunnar Mills * callback() 1403d500549bSAnthony Wilson * @endcode 1404d500549bSAnthony Wilson * 1405d500549bSAnthony Wilson * @param sensorsAsyncResp Pointer to object holding response data. 1406d500549bSAnthony Wilson * @param inventoryItems D-Bus inventory items associated with sensors. 1407d500549bSAnthony Wilson * @param callback Callback to invoke when inventory items have been obtained. 1408d500549bSAnthony Wilson */ 1409d500549bSAnthony Wilson template <typename Callback> 1410d500549bSAnthony Wilson void getInventoryLeds( 1411d500549bSAnthony Wilson std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 1412d500549bSAnthony Wilson std::shared_ptr<std::vector<InventoryItem>> inventoryItems, 1413d500549bSAnthony Wilson Callback&& callback) 1414d500549bSAnthony Wilson { 141562598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryLeds enter"); 1416d500549bSAnthony Wilson 1417d500549bSAnthony Wilson const std::string path = "/xyz/openbmc_project"; 1418e99073f5SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 1419d500549bSAnthony Wilson "xyz.openbmc_project.Led.Physical"}; 1420d500549bSAnthony Wilson 1421e99073f5SGeorge Liu // Make call to ObjectMapper to find all inventory items 1422e99073f5SGeorge Liu dbus::utility::getSubTree( 1423e99073f5SGeorge Liu path, 0, interfaces, 14248cb2c024SEd Tanous [callback = std::forward<Callback>(callback), sensorsAsyncResp, 1425002d39b4SEd Tanous inventoryItems]( 1426e99073f5SGeorge Liu const boost::system::error_code& ec, 14274e0d8789SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) mutable { 1428e99073f5SGeorge Liu // Response handler for parsing output from GetSubTree 142962598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryLeds respHandler enter"); 1430d500549bSAnthony Wilson if (ec) 1431d500549bSAnthony Wilson { 14328d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 1433bd79bce8SPatrick Williams BMCWEB_LOG_ERROR("getInventoryLeds respHandler DBus error {}", 1434bd79bce8SPatrick Williams ec); 1435d500549bSAnthony Wilson return; 1436d500549bSAnthony Wilson } 1437d500549bSAnthony Wilson 1438d500549bSAnthony Wilson // Build map of LED object paths to connections 1439fe04d49cSNan Zhou std::shared_ptr<std::map<std::string, std::string>> ledConnections = 1440fe04d49cSNan Zhou std::make_shared<std::map<std::string, std::string>>(); 1441d500549bSAnthony Wilson 1442d500549bSAnthony Wilson // Loop through objects from GetSubTree 1443bd79bce8SPatrick Williams for (const std::pair<std::string, 1444bd79bce8SPatrick Williams std::vector<std::pair< 1445bd79bce8SPatrick Williams std::string, std::vector<std::string>>>>& 1446d500549bSAnthony Wilson object : subtree) 1447d500549bSAnthony Wilson { 1448bd79bce8SPatrick Williams // Check if object path is LED for one of the specified 1449bd79bce8SPatrick Williams // inventory items 1450d500549bSAnthony Wilson const std::string& ledPath = object.first; 1451bd79bce8SPatrick Williams if (findInventoryItemForLed(*inventoryItems, ledPath) != 1452bd79bce8SPatrick Williams nullptr) 1453d500549bSAnthony Wilson { 1454d500549bSAnthony Wilson // Add mapping from ledPath to connection 1455bd79bce8SPatrick Williams const std::string& connection = 1456bd79bce8SPatrick Williams object.second.begin()->first; 1457d500549bSAnthony Wilson (*ledConnections)[ledPath] = connection; 1458bd79bce8SPatrick Williams BMCWEB_LOG_DEBUG("Added mapping {} -> {}", ledPath, 1459bd79bce8SPatrick Williams connection); 1460d500549bSAnthony Wilson } 1461d500549bSAnthony Wilson } 1462d500549bSAnthony Wilson 1463bd79bce8SPatrick Williams getInventoryLedData(sensorsAsyncResp, inventoryItems, 1464bd79bce8SPatrick Williams ledConnections, std::move(callback)); 146562598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryLeds respHandler exit"); 1466e99073f5SGeorge Liu }); 146762598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryLeds exit"); 1468d500549bSAnthony Wilson } 1469d500549bSAnthony Wilson 1470d500549bSAnthony Wilson /** 147142cbe538SGunnar Mills * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent 147242cbe538SGunnar Mills * 147342cbe538SGunnar Mills * Uses the specified connections (services) (currently assumes just one) to 147442cbe538SGunnar Mills * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in 147542cbe538SGunnar Mills * the inventoryItems vector. Only stores data in Power Supply inventoryItems. 147642cbe538SGunnar Mills * 147742cbe538SGunnar Mills * This data is later used to provide sensor property values in the JSON 147842cbe538SGunnar Mills * response. 147942cbe538SGunnar Mills * 148042cbe538SGunnar Mills * Finds the Power Supply Attributes data asynchronously. Invokes callback 148142cbe538SGunnar Mills * when data has been obtained. 148242cbe538SGunnar Mills * 148342cbe538SGunnar Mills * The callback must have the following signature: 148442cbe538SGunnar Mills * @code 148542cbe538SGunnar Mills * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems) 148642cbe538SGunnar Mills * @endcode 148742cbe538SGunnar Mills * 148842cbe538SGunnar Mills * @param sensorsAsyncResp Pointer to object holding response data. 148942cbe538SGunnar Mills * @param inventoryItems D-Bus inventory items associated with sensors. 149042cbe538SGunnar Mills * @param psAttributesConnections Connections that provide data for the Power 149142cbe538SGunnar Mills * Supply Attributes 149242cbe538SGunnar Mills * @param callback Callback to invoke when data has been obtained. 149342cbe538SGunnar Mills */ 149442cbe538SGunnar Mills template <typename Callback> 149542cbe538SGunnar Mills void getPowerSupplyAttributesData( 1496b5a76932SEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp, 149742cbe538SGunnar Mills std::shared_ptr<std::vector<InventoryItem>> inventoryItems, 1498fe04d49cSNan Zhou const std::map<std::string, std::string>& psAttributesConnections, 149942cbe538SGunnar Mills Callback&& callback) 150042cbe538SGunnar Mills { 150162598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData enter"); 150242cbe538SGunnar Mills 150342cbe538SGunnar Mills if (psAttributesConnections.empty()) 150442cbe538SGunnar Mills { 150562598e31SEd Tanous BMCWEB_LOG_DEBUG("Can't find PowerSupplyAttributes, no connections!"); 150642cbe538SGunnar Mills callback(inventoryItems); 150742cbe538SGunnar Mills return; 150842cbe538SGunnar Mills } 150942cbe538SGunnar Mills 151042cbe538SGunnar Mills // Assuming just one connection (service) for now 1511fe04d49cSNan Zhou auto it = psAttributesConnections.begin(); 151242cbe538SGunnar Mills 151342cbe538SGunnar Mills const std::string& psAttributesPath = (*it).first; 151442cbe538SGunnar Mills const std::string& psAttributesConnection = (*it).second; 151542cbe538SGunnar Mills 151642cbe538SGunnar Mills // Response handler for Get DeratingFactor property 15175a39f77aSPatrick Williams auto respHandler = [sensorsAsyncResp, inventoryItems, 15188cb2c024SEd Tanous callback = std::forward<Callback>(callback)]( 15195a39f77aSPatrick Williams const boost::system::error_code& ec, 15204e0d8789SEd Tanous uint32_t value) mutable { 152162598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler enter"); 152242cbe538SGunnar Mills if (ec) 152342cbe538SGunnar Mills { 152462598e31SEd Tanous BMCWEB_LOG_ERROR( 152562598e31SEd Tanous "getPowerSupplyAttributesData respHandler DBus error {}", ec); 15268d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 152742cbe538SGunnar Mills return; 152842cbe538SGunnar Mills } 152942cbe538SGunnar Mills 153062598e31SEd Tanous BMCWEB_LOG_DEBUG("PS EfficiencyPercent value: {}", value); 153142cbe538SGunnar Mills // Store value in Power Supply Inventory Items 153242cbe538SGunnar Mills for (InventoryItem& inventoryItem : *inventoryItems) 153342cbe538SGunnar Mills { 153455f79e6fSEd Tanous if (inventoryItem.isPowerSupply) 153542cbe538SGunnar Mills { 153642cbe538SGunnar Mills inventoryItem.powerSupplyEfficiencyPercent = 15371e1e598dSJonathan Doman static_cast<int>(value); 153842cbe538SGunnar Mills } 153942cbe538SGunnar Mills } 154042cbe538SGunnar Mills 154162598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler exit"); 154242cbe538SGunnar Mills callback(inventoryItems); 154342cbe538SGunnar Mills }; 154442cbe538SGunnar Mills 154542cbe538SGunnar Mills // Get the DeratingFactor property for the PowerSupplyAttributes 154642cbe538SGunnar Mills // Currently only property on the interface/only one we care about 15471e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint32_t>( 15481e1e598dSJonathan Doman *crow::connections::systemBus, psAttributesConnection, psAttributesPath, 15491e1e598dSJonathan Doman "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor", 15501e1e598dSJonathan Doman std::move(respHandler)); 155142cbe538SGunnar Mills 155262598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData exit"); 155342cbe538SGunnar Mills } 155442cbe538SGunnar Mills 155542cbe538SGunnar Mills /** 155642cbe538SGunnar Mills * @brief Gets the Power Supply Attributes such as EfficiencyPercent 155742cbe538SGunnar Mills * 155842cbe538SGunnar Mills * Gets the D-Bus connection (service) that provides Power Supply Attributes 155942cbe538SGunnar Mills * data. Then gets the Power Supply Attributes data from the connection 156042cbe538SGunnar Mills * (currently just assumes 1 connection) and stores the data in the inventory 156142cbe538SGunnar Mills * item. 156242cbe538SGunnar Mills * 156342cbe538SGunnar Mills * This data is later used to provide sensor property values in the JSON 156442cbe538SGunnar Mills * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish. 156542cbe538SGunnar Mills * 156642cbe538SGunnar Mills * Finds the Power Supply Attributes data asynchronously. Invokes callback 156742cbe538SGunnar Mills * when information has been obtained. 156842cbe538SGunnar Mills * 156942cbe538SGunnar Mills * The callback must have the following signature: 157042cbe538SGunnar Mills * @code 157142cbe538SGunnar Mills * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems) 157242cbe538SGunnar Mills * @endcode 157342cbe538SGunnar Mills * 157442cbe538SGunnar Mills * @param sensorsAsyncResp Pointer to object holding response data. 157542cbe538SGunnar Mills * @param inventoryItems D-Bus inventory items associated with sensors. 157642cbe538SGunnar Mills * @param callback Callback to invoke when data has been obtained. 157742cbe538SGunnar Mills */ 157842cbe538SGunnar Mills template <typename Callback> 157942cbe538SGunnar Mills void getPowerSupplyAttributes( 158042cbe538SGunnar Mills std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 158142cbe538SGunnar Mills std::shared_ptr<std::vector<InventoryItem>> inventoryItems, 158242cbe538SGunnar Mills Callback&& callback) 158342cbe538SGunnar Mills { 158462598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributes enter"); 158542cbe538SGunnar Mills 158642cbe538SGunnar Mills // Only need the power supply attributes when the Power Schema 15870c728b42SJanet Adkins if (sensorsAsyncResp->chassisSubNode != sensors::powerNodeStr) 158842cbe538SGunnar Mills { 158962598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit since not Power"); 159042cbe538SGunnar Mills callback(inventoryItems); 159142cbe538SGunnar Mills return; 159242cbe538SGunnar Mills } 159342cbe538SGunnar Mills 1594e99073f5SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 159542cbe538SGunnar Mills "xyz.openbmc_project.Control.PowerSupplyAttributes"}; 159642cbe538SGunnar Mills 1597e99073f5SGeorge Liu // Make call to ObjectMapper to find the PowerSupplyAttributes service 1598e99073f5SGeorge Liu dbus::utility::getSubTree( 1599e99073f5SGeorge Liu "/xyz/openbmc_project", 0, interfaces, 16008cb2c024SEd Tanous [callback = std::forward<Callback>(callback), sensorsAsyncResp, 1601b9d36b47SEd Tanous inventoryItems]( 1602e99073f5SGeorge Liu const boost::system::error_code& ec, 16034e0d8789SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) mutable { 1604e99073f5SGeorge Liu // Response handler for parsing output from GetSubTree 160562598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler enter"); 160642cbe538SGunnar Mills if (ec) 160742cbe538SGunnar Mills { 16088d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 160962598e31SEd Tanous BMCWEB_LOG_ERROR( 161062598e31SEd Tanous "getPowerSupplyAttributes respHandler DBus error {}", ec); 161142cbe538SGunnar Mills return; 161242cbe538SGunnar Mills } 161326f6976fSEd Tanous if (subtree.empty()) 161442cbe538SGunnar Mills { 161562598e31SEd Tanous BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!"); 161642cbe538SGunnar Mills callback(inventoryItems); 161742cbe538SGunnar Mills return; 161842cbe538SGunnar Mills } 161942cbe538SGunnar Mills 162042cbe538SGunnar Mills // Currently we only support 1 power supply attribute, use this for 162142cbe538SGunnar Mills // all the power supplies. Build map of object path to connection. 162242cbe538SGunnar Mills // Assume just 1 connection and 1 path for now. 1623fe04d49cSNan Zhou std::map<std::string, std::string> psAttributesConnections; 162442cbe538SGunnar Mills 162542cbe538SGunnar Mills if (subtree[0].first.empty() || subtree[0].second.empty()) 162642cbe538SGunnar Mills { 162762598e31SEd Tanous BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!"); 162842cbe538SGunnar Mills callback(inventoryItems); 162942cbe538SGunnar Mills return; 163042cbe538SGunnar Mills } 163142cbe538SGunnar Mills 163242cbe538SGunnar Mills const std::string& psAttributesPath = subtree[0].first; 163342cbe538SGunnar Mills const std::string& connection = subtree[0].second.begin()->first; 163442cbe538SGunnar Mills 163542cbe538SGunnar Mills if (connection.empty()) 163642cbe538SGunnar Mills { 163762598e31SEd Tanous BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!"); 163842cbe538SGunnar Mills callback(inventoryItems); 163942cbe538SGunnar Mills return; 164042cbe538SGunnar Mills } 164142cbe538SGunnar Mills 164242cbe538SGunnar Mills psAttributesConnections[psAttributesPath] = connection; 164362598e31SEd Tanous BMCWEB_LOG_DEBUG("Added mapping {} -> {}", psAttributesPath, 164462598e31SEd Tanous connection); 164542cbe538SGunnar Mills 164642cbe538SGunnar Mills getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems, 164742cbe538SGunnar Mills psAttributesConnections, 164842cbe538SGunnar Mills std::move(callback)); 164962598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler exit"); 1650e99073f5SGeorge Liu }); 165162598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit"); 165242cbe538SGunnar Mills } 165342cbe538SGunnar Mills 165442cbe538SGunnar Mills /** 1655adc4f0dbSShawn McCarney * @brief Gets inventory items associated with sensors. 16568fb49dd6SShawn McCarney * 16578fb49dd6SShawn McCarney * Finds the inventory items that are associated with the specified sensors. 1658adc4f0dbSShawn McCarney * Then gets D-Bus data for the inventory items, such as presence and VPD. 16598fb49dd6SShawn McCarney * 1660adc4f0dbSShawn McCarney * This data is later used to provide sensor property values in the JSON 1661adc4f0dbSShawn McCarney * response. 16628fb49dd6SShawn McCarney * 1663adc4f0dbSShawn McCarney * Finds the inventory items asynchronously. Invokes callback when the 1664adc4f0dbSShawn McCarney * inventory items have been obtained. 1665adc4f0dbSShawn McCarney * 1666adc4f0dbSShawn McCarney * The callback must have the following signature: 1667adc4f0dbSShawn McCarney * @code 1668adc4f0dbSShawn McCarney * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems) 1669adc4f0dbSShawn McCarney * @endcode 16708fb49dd6SShawn McCarney * 16718fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 16728fb49dd6SShawn McCarney * @param sensorNames All sensors within the current chassis. 16738fb49dd6SShawn McCarney * implements ObjectManager. 1674adc4f0dbSShawn McCarney * @param callback Callback to invoke when inventory items have been obtained. 16758fb49dd6SShawn McCarney */ 1676adc4f0dbSShawn McCarney template <typename Callback> 16774ff0f1f4SEd Tanous inline void 1678d0090733SEd Tanous getInventoryItems(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 1679fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>> sensorNames, 1680adc4f0dbSShawn McCarney Callback&& callback) 16818fb49dd6SShawn McCarney { 168262598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItems enter"); 1683adc4f0dbSShawn McCarney auto getInventoryItemAssociationsCb = 16848cb2c024SEd Tanous [sensorsAsyncResp, callback = std::forward<Callback>(callback)]( 16854e0d8789SEd Tanous std::shared_ptr<std::vector<InventoryItem>> 16864e0d8789SEd Tanous inventoryItems) mutable { 168762598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb enter"); 16888fb49dd6SShawn McCarney auto getInventoryItemsConnectionsCb = 1689d0090733SEd Tanous [sensorsAsyncResp, inventoryItems, 16904e0d8789SEd Tanous callback = std::forward<Callback>(callback)]( 16914e0d8789SEd Tanous std::shared_ptr<std::set<std::string>> 16924e0d8789SEd Tanous invConnections) mutable { 169362598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb enter"); 1694bd79bce8SPatrick Williams auto getInventoryItemsDataCb = 1695bd79bce8SPatrick Williams [sensorsAsyncResp, inventoryItems, 16964e0d8789SEd Tanous callback = 16974e0d8789SEd Tanous std::forward<Callback>(callback)]() mutable { 169862598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsDataCb enter"); 169942cbe538SGunnar Mills 1700bd79bce8SPatrick Williams auto getInventoryLedsCb = 1701bd79bce8SPatrick Williams [sensorsAsyncResp, inventoryItems, 17024e0d8789SEd Tanous callback = std::forward<Callback>( 17034e0d8789SEd Tanous callback)]() mutable { 1704bd79bce8SPatrick Williams BMCWEB_LOG_DEBUG( 1705bd79bce8SPatrick Williams "getInventoryLedsCb enter"); 1706bd79bce8SPatrick Williams // Find Power Supply Attributes and get the 1707bd79bce8SPatrick Williams // data 1708bd79bce8SPatrick Williams getPowerSupplyAttributes( 1709bd79bce8SPatrick Williams sensorsAsyncResp, inventoryItems, 171042cbe538SGunnar Mills std::move(callback)); 171162598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryLedsCb exit"); 171242cbe538SGunnar Mills }; 171342cbe538SGunnar Mills 1714d500549bSAnthony Wilson // Find led connections and get the data 1715d500549bSAnthony Wilson getInventoryLeds(sensorsAsyncResp, inventoryItems, 171642cbe538SGunnar Mills std::move(getInventoryLedsCb)); 171762598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsDataCb exit"); 1718d500549bSAnthony Wilson }; 17198fb49dd6SShawn McCarney 1720adc4f0dbSShawn McCarney // Get inventory item data from connections 1721adc4f0dbSShawn McCarney getInventoryItemsData(sensorsAsyncResp, inventoryItems, 1722d0090733SEd Tanous invConnections, 1723d500549bSAnthony Wilson std::move(getInventoryItemsDataCb)); 172462598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb exit"); 17258fb49dd6SShawn McCarney }; 17268fb49dd6SShawn McCarney 1727adc4f0dbSShawn McCarney // Get connections that provide inventory item data 1728bd79bce8SPatrick Williams getInventoryItemsConnections( 1729bd79bce8SPatrick Williams sensorsAsyncResp, inventoryItems, 17308fb49dd6SShawn McCarney std::move(getInventoryItemsConnectionsCb)); 173162598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb exit"); 17328fb49dd6SShawn McCarney }; 17338fb49dd6SShawn McCarney 1734adc4f0dbSShawn McCarney // Get associations from sensors to inventory items 1735d0090733SEd Tanous getInventoryItemAssociations(sensorsAsyncResp, sensorNames, 1736adc4f0dbSShawn McCarney std::move(getInventoryItemAssociationsCb)); 173762598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItems exit"); 1738adc4f0dbSShawn McCarney } 1739adc4f0dbSShawn McCarney 1740adc4f0dbSShawn McCarney /** 1741adc4f0dbSShawn McCarney * @brief Returns JSON PowerSupply object for the specified inventory item. 1742adc4f0dbSShawn McCarney * 1743adc4f0dbSShawn McCarney * Searches for a JSON PowerSupply object that matches the specified inventory 1744adc4f0dbSShawn McCarney * item. If one is not found, a new PowerSupply object is added to the JSON 1745adc4f0dbSShawn McCarney * array. 1746adc4f0dbSShawn McCarney * 1747adc4f0dbSShawn McCarney * Multiple sensors are often associated with one power supply inventory item. 1748adc4f0dbSShawn McCarney * As a result, multiple sensor values are stored in one JSON PowerSupply 1749adc4f0dbSShawn McCarney * object. 1750adc4f0dbSShawn McCarney * 1751adc4f0dbSShawn McCarney * @param powerSupplyArray JSON array containing Redfish PowerSupply objects. 1752adc4f0dbSShawn McCarney * @param inventoryItem Inventory item for the power supply. 1753adc4f0dbSShawn McCarney * @param chassisId Chassis that contains the power supply. 1754adc4f0dbSShawn McCarney * @return JSON PowerSupply object for the specified inventory item. 1755adc4f0dbSShawn McCarney */ 175623a21a1cSEd Tanous inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray, 1757adc4f0dbSShawn McCarney const InventoryItem& inventoryItem, 1758adc4f0dbSShawn McCarney const std::string& chassisId) 1759adc4f0dbSShawn McCarney { 176018f8f608SEd Tanous std::string nameS; 17616f4bd290SAlexander Hansen nameS.resize(inventoryItem.name.size()); 176218f8f608SEd Tanous std::ranges::replace_copy(inventoryItem.name, nameS.begin(), '_', ' '); 1763adc4f0dbSShawn McCarney // Check if matching PowerSupply object already exists in JSON array 1764adc4f0dbSShawn McCarney for (nlohmann::json& powerSupply : powerSupplyArray) 1765adc4f0dbSShawn McCarney { 176618f8f608SEd Tanous nlohmann::json::iterator nameIt = powerSupply.find("Name"); 176718f8f608SEd Tanous if (nameIt == powerSupply.end()) 176818f8f608SEd Tanous { 176918f8f608SEd Tanous continue; 177018f8f608SEd Tanous } 177118f8f608SEd Tanous const std::string* name = nameIt->get_ptr<std::string*>(); 177218f8f608SEd Tanous if (name == nullptr) 177318f8f608SEd Tanous { 177418f8f608SEd Tanous continue; 177518f8f608SEd Tanous } 177618f8f608SEd Tanous if (nameS == *name) 1777adc4f0dbSShawn McCarney { 1778adc4f0dbSShawn McCarney return powerSupply; 1779adc4f0dbSShawn McCarney } 1780adc4f0dbSShawn McCarney } 1781adc4f0dbSShawn McCarney 1782adc4f0dbSShawn McCarney // Add new PowerSupply object to JSON array 1783adc4f0dbSShawn McCarney powerSupplyArray.push_back({}); 1784adc4f0dbSShawn McCarney nlohmann::json& powerSupply = powerSupplyArray.back(); 1785bd79bce8SPatrick Williams boost::urls::url url = 1786bd79bce8SPatrick Williams boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId); 1787eddfc437SWilly Tu url.set_fragment(("/PowerSupplies"_json_pointer).to_string()); 1788eddfc437SWilly Tu powerSupply["@odata.id"] = std::move(url); 178918f8f608SEd Tanous std::string escaped; 17906f4bd290SAlexander Hansen escaped.resize(inventoryItem.name.size()); 179118f8f608SEd Tanous std::ranges::replace_copy(inventoryItem.name, escaped.begin(), '_', ' '); 179218f8f608SEd Tanous powerSupply["Name"] = std::move(escaped); 1793adc4f0dbSShawn McCarney powerSupply["Manufacturer"] = inventoryItem.manufacturer; 1794adc4f0dbSShawn McCarney powerSupply["Model"] = inventoryItem.model; 1795adc4f0dbSShawn McCarney powerSupply["PartNumber"] = inventoryItem.partNumber; 1796adc4f0dbSShawn McCarney powerSupply["SerialNumber"] = inventoryItem.serialNumber; 1797c9563608SJanet Adkins sensor_utils::setLedState(powerSupply, &inventoryItem); 1798adc4f0dbSShawn McCarney 179942cbe538SGunnar Mills if (inventoryItem.powerSupplyEfficiencyPercent >= 0) 180042cbe538SGunnar Mills { 180142cbe538SGunnar Mills powerSupply["EfficiencyPercent"] = 180242cbe538SGunnar Mills inventoryItem.powerSupplyEfficiencyPercent; 180342cbe538SGunnar Mills } 180442cbe538SGunnar Mills 1805c9563608SJanet Adkins powerSupply["Status"]["State"] = 1806c9563608SJanet Adkins sensor_utils::getState(&inventoryItem, true); 1807adc4f0dbSShawn McCarney const char* health = inventoryItem.isFunctional ? "OK" : "Critical"; 1808adc4f0dbSShawn McCarney powerSupply["Status"]["Health"] = health; 1809adc4f0dbSShawn McCarney 1810adc4f0dbSShawn McCarney return powerSupply; 18118fb49dd6SShawn McCarney } 18128fb49dd6SShawn McCarney 18138fb49dd6SShawn McCarney /** 1814de629b6eSShawn McCarney * @brief Gets the values of the specified sensors. 1815de629b6eSShawn McCarney * 1816de629b6eSShawn McCarney * Stores the results as JSON in the SensorsAsyncResp. 1817de629b6eSShawn McCarney * 1818de629b6eSShawn McCarney * Gets the sensor values asynchronously. Stores the results later when the 1819de629b6eSShawn McCarney * information has been obtained. 1820de629b6eSShawn McCarney * 1821adc4f0dbSShawn McCarney * The sensorNames set contains all requested sensors for the current chassis. 1822de629b6eSShawn McCarney * 1823de629b6eSShawn McCarney * To minimize the number of DBus calls, the DBus method 1824de629b6eSShawn McCarney * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the 1825de629b6eSShawn McCarney * values of all sensors provided by a connection (service). 1826de629b6eSShawn McCarney * 1827de629b6eSShawn McCarney * The connections set contains all the connections that provide sensor values. 1828de629b6eSShawn McCarney * 1829adc4f0dbSShawn McCarney * The InventoryItem vector contains D-Bus inventory items associated with the 1830adc4f0dbSShawn McCarney * sensors. Inventory item data is needed for some Redfish sensor properties. 1831adc4f0dbSShawn McCarney * 1832de629b6eSShawn McCarney * @param SensorsAsyncResp Pointer to object holding response data. 1833adc4f0dbSShawn McCarney * @param sensorNames All requested sensors within the current chassis. 1834de629b6eSShawn McCarney * @param connections Connections that provide sensor values. 1835de629b6eSShawn McCarney * implements ObjectManager. 1836adc4f0dbSShawn McCarney * @param inventoryItems Inventory items associated with the sensors. 1837de629b6eSShawn McCarney */ 183823a21a1cSEd Tanous inline void getSensorData( 183981ce609eSEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp, 1840fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& sensorNames, 1841fe04d49cSNan Zhou const std::set<std::string>& connections, 1842b5a76932SEd Tanous const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems) 1843de629b6eSShawn McCarney { 184462598e31SEd Tanous BMCWEB_LOG_DEBUG("getSensorData enter"); 1845de629b6eSShawn McCarney // Get managed objects from all services exposing sensors 1846de629b6eSShawn McCarney for (const std::string& connection : connections) 1847de629b6eSShawn McCarney { 18485eb468daSGeorge Liu sdbusplus::message::object_path sensorPath( 18495eb468daSGeorge Liu "/xyz/openbmc_project/sensors"); 18505eb468daSGeorge Liu dbus::utility::getManagedObjects( 18515eb468daSGeorge Liu connection, sensorPath, 1852002d39b4SEd Tanous [sensorsAsyncResp, sensorNames, 18535e7e2dc5SEd Tanous inventoryItems](const boost::system::error_code& ec, 185402cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 185562598e31SEd Tanous BMCWEB_LOG_DEBUG("getManagedObjectsCb enter"); 1856de629b6eSShawn McCarney if (ec) 1857de629b6eSShawn McCarney { 185862598e31SEd Tanous BMCWEB_LOG_ERROR("getManagedObjectsCb DBUS error: {}", ec); 18598d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 1860de629b6eSShawn McCarney return; 1861de629b6eSShawn McCarney } 18620c728b42SJanet Adkins auto chassisSubNode = sensor_utils::chassisSubNodeFromString( 18630c728b42SJanet Adkins sensorsAsyncResp->chassisSubNode); 1864de629b6eSShawn McCarney // Go through all objects and update response with sensor data 1865de629b6eSShawn McCarney for (const auto& objDictEntry : resp) 1866de629b6eSShawn McCarney { 1867de629b6eSShawn McCarney const std::string& objPath = 1868de629b6eSShawn McCarney static_cast<const std::string&>(objDictEntry.first); 186962598e31SEd Tanous BMCWEB_LOG_DEBUG("getManagedObjectsCb parsing object {}", 187062598e31SEd Tanous objPath); 1871de629b6eSShawn McCarney 1872de629b6eSShawn McCarney std::vector<std::string> split; 1873de629b6eSShawn McCarney // Reserve space for 1874de629b6eSShawn McCarney // /xyz/openbmc_project/sensors/<name>/<subname> 1875de629b6eSShawn McCarney split.reserve(6); 187650ebd4afSEd Tanous // NOLINTNEXTLINE 187750ebd4afSEd Tanous bmcweb::split(split, objPath, '/'); 1878de629b6eSShawn McCarney if (split.size() < 6) 1879de629b6eSShawn McCarney { 188062598e31SEd Tanous BMCWEB_LOG_ERROR("Got path that isn't long enough {}", 188162598e31SEd Tanous objPath); 1882de629b6eSShawn McCarney continue; 1883de629b6eSShawn McCarney } 188450ebd4afSEd Tanous // These indexes aren't intuitive, as split puts an empty 1885de629b6eSShawn McCarney // string at the beginning 1886de629b6eSShawn McCarney const std::string& sensorType = split[4]; 1887de629b6eSShawn McCarney const std::string& sensorName = split[5]; 188862598e31SEd Tanous BMCWEB_LOG_DEBUG("sensorName {} sensorType {}", sensorName, 188962598e31SEd Tanous sensorType); 189049c53ac9SJohnathan Mantey if (sensorNames->find(objPath) == sensorNames->end()) 1891de629b6eSShawn McCarney { 189262598e31SEd Tanous BMCWEB_LOG_DEBUG("{} not in sensor list ", sensorName); 1893de629b6eSShawn McCarney continue; 1894de629b6eSShawn McCarney } 1895de629b6eSShawn McCarney 1896adc4f0dbSShawn McCarney // Find inventory item (if any) associated with sensor 1897adc4f0dbSShawn McCarney InventoryItem* inventoryItem = 1898adc4f0dbSShawn McCarney findInventoryItemForSensor(inventoryItems, objPath); 1899adc4f0dbSShawn McCarney 190095a3ecadSAnthony Wilson const std::string& sensorSchema = 190181ce609eSEd Tanous sensorsAsyncResp->chassisSubNode; 190295a3ecadSAnthony Wilson 190395a3ecadSAnthony Wilson nlohmann::json* sensorJson = nullptr; 190495a3ecadSAnthony Wilson 19050c728b42SJanet Adkins if (sensorSchema == sensors::sensorsNodeStr && 1906928fefb9SNan Zhou !sensorsAsyncResp->efficientExpand) 190795a3ecadSAnthony Wilson { 19081516c21bSJanet Adkins std::string sensorId = 19091516c21bSJanet Adkins redfish::sensor_utils::getSensorId(sensorName, 19101516c21bSJanet Adkins sensorType); 1911c1d019a6SEd Tanous 1912bd79bce8SPatrick Williams sensorsAsyncResp->asyncResp->res 1913bd79bce8SPatrick Williams .jsonValue["@odata.id"] = boost::urls::format( 1914bd79bce8SPatrick Williams "/redfish/v1/Chassis/{}/{}/{}", 1915c1d019a6SEd Tanous sensorsAsyncResp->chassisId, 1916bd79bce8SPatrick Williams sensorsAsyncResp->chassisSubNode, sensorId); 1917bd79bce8SPatrick Williams sensorJson = 1918bd79bce8SPatrick Williams &(sensorsAsyncResp->asyncResp->res.jsonValue); 191995a3ecadSAnthony Wilson } 192095a3ecadSAnthony Wilson else 192195a3ecadSAnthony Wilson { 1922271584abSEd Tanous std::string fieldName; 1923928fefb9SNan Zhou if (sensorsAsyncResp->efficientExpand) 1924928fefb9SNan Zhou { 1925928fefb9SNan Zhou fieldName = "Members"; 1926928fefb9SNan Zhou } 1927928fefb9SNan Zhou else if (sensorType == "temperature") 1928de629b6eSShawn McCarney { 1929de629b6eSShawn McCarney fieldName = "Temperatures"; 1930de629b6eSShawn McCarney } 1931bd79bce8SPatrick Williams else if (sensorType == "fan" || 1932bd79bce8SPatrick Williams sensorType == "fan_tach" || 1933de629b6eSShawn McCarney sensorType == "fan_pwm") 1934de629b6eSShawn McCarney { 1935de629b6eSShawn McCarney fieldName = "Fans"; 1936de629b6eSShawn McCarney } 1937de629b6eSShawn McCarney else if (sensorType == "voltage") 1938de629b6eSShawn McCarney { 1939de629b6eSShawn McCarney fieldName = "Voltages"; 1940de629b6eSShawn McCarney } 1941de629b6eSShawn McCarney else if (sensorType == "power") 1942de629b6eSShawn McCarney { 194355f79e6fSEd Tanous if (sensorName == "total_power") 1944028f7ebcSEddie James { 1945028f7ebcSEddie James fieldName = "PowerControl"; 1946028f7ebcSEddie James } 1947adc4f0dbSShawn McCarney else if ((inventoryItem != nullptr) && 1948adc4f0dbSShawn McCarney (inventoryItem->isPowerSupply)) 1949028f7ebcSEddie James { 1950de629b6eSShawn McCarney fieldName = "PowerSupplies"; 1951de629b6eSShawn McCarney } 1952adc4f0dbSShawn McCarney else 1953adc4f0dbSShawn McCarney { 1954adc4f0dbSShawn McCarney // Other power sensors are in SensorCollection 1955adc4f0dbSShawn McCarney continue; 1956adc4f0dbSShawn McCarney } 1957028f7ebcSEddie James } 1958de629b6eSShawn McCarney else 1959de629b6eSShawn McCarney { 1960bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 1961bd79bce8SPatrick Williams "Unsure how to handle sensorType {}", 196262598e31SEd Tanous sensorType); 1963de629b6eSShawn McCarney continue; 1964de629b6eSShawn McCarney } 1965de629b6eSShawn McCarney 1966de629b6eSShawn McCarney nlohmann::json& tempArray = 1967bd79bce8SPatrick Williams sensorsAsyncResp->asyncResp->res 1968bd79bce8SPatrick Williams .jsonValue[fieldName]; 1969adc4f0dbSShawn McCarney if (fieldName == "PowerControl") 197049c53ac9SJohnathan Mantey { 1971adc4f0dbSShawn McCarney if (tempArray.empty()) 19727ab06f49SGunnar Mills { 197395a3ecadSAnthony Wilson // Put multiple "sensors" into a single 197495a3ecadSAnthony Wilson // PowerControl. Follows MemberId naming and 197595a3ecadSAnthony Wilson // naming in power.hpp. 19761476687dSEd Tanous nlohmann::json::object_t power; 1977ef4c65b7SEd Tanous boost::urls::url url = boost::urls::format( 1978ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/{}", 1979eddfc437SWilly Tu sensorsAsyncResp->chassisId, 1980eddfc437SWilly Tu sensorsAsyncResp->chassisSubNode); 1981bd79bce8SPatrick Williams url.set_fragment( 1982bd79bce8SPatrick Williams (""_json_pointer / fieldName / "0") 1983eddfc437SWilly Tu .to_string()); 1984eddfc437SWilly Tu power["@odata.id"] = std::move(url); 1985b2ba3072SPatrick Williams tempArray.emplace_back(std::move(power)); 1986adc4f0dbSShawn McCarney } 1987adc4f0dbSShawn McCarney sensorJson = &(tempArray.back()); 1988adc4f0dbSShawn McCarney } 1989adc4f0dbSShawn McCarney else if (fieldName == "PowerSupplies") 1990adc4f0dbSShawn McCarney { 1991adc4f0dbSShawn McCarney if (inventoryItem != nullptr) 1992adc4f0dbSShawn McCarney { 1993bd79bce8SPatrick Williams sensorJson = &(getPowerSupply( 1994bd79bce8SPatrick Williams tempArray, *inventoryItem, 199581ce609eSEd Tanous sensorsAsyncResp->chassisId)); 1996adc4f0dbSShawn McCarney } 199749c53ac9SJohnathan Mantey } 1998928fefb9SNan Zhou else if (fieldName == "Members") 1999928fefb9SNan Zhou { 20001516c21bSJanet Adkins std::string sensorId = 20011516c21bSJanet Adkins redfish::sensor_utils::getSensorId(sensorName, 20021516c21bSJanet Adkins sensorType); 2003677bb756SEd Tanous 20041476687dSEd Tanous nlohmann::json::object_t member; 2005ef4c65b7SEd Tanous member["@odata.id"] = boost::urls::format( 2006ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/{}/{}", 2007677bb756SEd Tanous sensorsAsyncResp->chassisId, 2008677bb756SEd Tanous sensorsAsyncResp->chassisSubNode, sensorId); 2009b2ba3072SPatrick Williams tempArray.emplace_back(std::move(member)); 2010928fefb9SNan Zhou sensorJson = &(tempArray.back()); 2011928fefb9SNan Zhou } 201249c53ac9SJohnathan Mantey else 201349c53ac9SJohnathan Mantey { 20141476687dSEd Tanous nlohmann::json::object_t member; 2015ef4c65b7SEd Tanous boost::urls::url url = boost::urls::format( 2016ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/{}", 2017eddfc437SWilly Tu sensorsAsyncResp->chassisId, 2018eddfc437SWilly Tu sensorsAsyncResp->chassisSubNode); 2019eddfc437SWilly Tu url.set_fragment( 2020eddfc437SWilly Tu (""_json_pointer / fieldName).to_string()); 2021eddfc437SWilly Tu member["@odata.id"] = std::move(url); 2022b2ba3072SPatrick Williams tempArray.emplace_back(std::move(member)); 2023adc4f0dbSShawn McCarney sensorJson = &(tempArray.back()); 202449c53ac9SJohnathan Mantey } 202595a3ecadSAnthony Wilson } 2026de629b6eSShawn McCarney 2027adc4f0dbSShawn McCarney if (sensorJson != nullptr) 2028adc4f0dbSShawn McCarney { 20290c728b42SJanet Adkins objectInterfacesToJson( 20300c728b42SJanet Adkins sensorName, sensorType, chassisSubNode, 20310c728b42SJanet Adkins objDictEntry.second, *sensorJson, inventoryItem); 20321d7c0054SEd Tanous 20331d7c0054SEd Tanous std::string path = "/xyz/openbmc_project/sensors/"; 20341d7c0054SEd Tanous path += sensorType; 20351d7c0054SEd Tanous path += "/"; 20361d7c0054SEd Tanous path += sensorName; 2037c1d019a6SEd Tanous sensorsAsyncResp->addMetadata(*sensorJson, path); 2038adc4f0dbSShawn McCarney } 2039de629b6eSShawn McCarney } 204081ce609eSEd Tanous if (sensorsAsyncResp.use_count() == 1) 204149c53ac9SJohnathan Mantey { 204281ce609eSEd Tanous sortJSONResponse(sensorsAsyncResp); 20430c728b42SJanet Adkins if (chassisSubNode == 20440c728b42SJanet Adkins sensor_utils::ChassisSubNode::sensorsNode && 2045928fefb9SNan Zhou sensorsAsyncResp->efficientExpand) 2046928fefb9SNan Zhou { 2047928fefb9SNan Zhou sensorsAsyncResp->asyncResp->res 2048928fefb9SNan Zhou .jsonValue["Members@odata.count"] = 2049bd79bce8SPatrick Williams sensorsAsyncResp->asyncResp->res 2050bd79bce8SPatrick Williams .jsonValue["Members"] 2051928fefb9SNan Zhou .size(); 2052928fefb9SNan Zhou } 20530c728b42SJanet Adkins else if (chassisSubNode == 20540c728b42SJanet Adkins sensor_utils::ChassisSubNode::thermalNode) 20558bd25ccdSJames Feist { 205681ce609eSEd Tanous populateFanRedundancy(sensorsAsyncResp); 20578bd25ccdSJames Feist } 205849c53ac9SJohnathan Mantey } 205962598e31SEd Tanous BMCWEB_LOG_DEBUG("getManagedObjectsCb exit"); 20605eb468daSGeorge Liu }); 206123a21a1cSEd Tanous } 206262598e31SEd Tanous BMCWEB_LOG_DEBUG("getSensorData exit"); 2063de629b6eSShawn McCarney } 2064de629b6eSShawn McCarney 2065fe04d49cSNan Zhou inline void 2066fe04d49cSNan Zhou processSensorList(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp, 2067fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& sensorNames) 20681abe55efSEd Tanous { 2069fe04d49cSNan Zhou auto getConnectionCb = [sensorsAsyncResp, sensorNames]( 2070fe04d49cSNan Zhou const std::set<std::string>& connections) { 207162598e31SEd Tanous BMCWEB_LOG_DEBUG("getConnectionCb enter"); 2072adc4f0dbSShawn McCarney auto getInventoryItemsCb = 2073bd79bce8SPatrick Williams [sensorsAsyncResp, sensorNames, connections]( 2074bd79bce8SPatrick Williams const std::shared_ptr<std::vector<InventoryItem>>& 20754e0d8789SEd Tanous inventoryItems) mutable { 207662598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsCb enter"); 207749c53ac9SJohnathan Mantey // Get sensor data and store results in JSON 2078002d39b4SEd Tanous getSensorData(sensorsAsyncResp, sensorNames, connections, 2079d0090733SEd Tanous inventoryItems); 208062598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsCb exit"); 2081adc4f0dbSShawn McCarney }; 2082adc4f0dbSShawn McCarney 2083adc4f0dbSShawn McCarney // Get inventory items associated with sensors 2084d0090733SEd Tanous getInventoryItems(sensorsAsyncResp, sensorNames, 2085adc4f0dbSShawn McCarney std::move(getInventoryItemsCb)); 2086adc4f0dbSShawn McCarney 208762598e31SEd Tanous BMCWEB_LOG_DEBUG("getConnectionCb exit"); 208808777fb0SLewanczyk, Dawid }; 2089de629b6eSShawn McCarney 2090de629b6eSShawn McCarney // Get set of connections that provide sensor values 209181ce609eSEd Tanous getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb)); 209295a3ecadSAnthony Wilson } 209395a3ecadSAnthony Wilson 209495a3ecadSAnthony Wilson /** 209595a3ecadSAnthony Wilson * @brief Entry point for retrieving sensors data related to requested 209695a3ecadSAnthony Wilson * chassis. 209795a3ecadSAnthony Wilson * @param SensorsAsyncResp Pointer to object holding response data 209895a3ecadSAnthony Wilson */ 2099b5a76932SEd Tanous inline void 210081ce609eSEd Tanous getChassisData(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp) 210195a3ecadSAnthony Wilson { 210262598e31SEd Tanous BMCWEB_LOG_DEBUG("getChassisData enter"); 210395a3ecadSAnthony Wilson auto getChassisCb = 210481ce609eSEd Tanous [sensorsAsyncResp]( 2105fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& sensorNames) { 210662598e31SEd Tanous BMCWEB_LOG_DEBUG("getChassisCb enter"); 210781ce609eSEd Tanous processSensorList(sensorsAsyncResp, sensorNames); 210862598e31SEd Tanous BMCWEB_LOG_DEBUG("getChassisCb exit"); 210908777fb0SLewanczyk, Dawid }; 2110928fefb9SNan Zhou // SensorCollection doesn't contain the Redundancy property 21110c728b42SJanet Adkins if (sensorsAsyncResp->chassisSubNode != sensors::sensorsNodeStr) 2112928fefb9SNan Zhou { 21138d1b46d7Szhanghch05 sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] = 21148d1b46d7Szhanghch05 nlohmann::json::array(); 2115928fefb9SNan Zhou } 211626f03899SShawn McCarney // Get set of sensors in chassis 21177f1cc26dSEd Tanous getChassis(sensorsAsyncResp->asyncResp, sensorsAsyncResp->chassisId, 21187f1cc26dSEd Tanous sensorsAsyncResp->chassisSubNode, sensorsAsyncResp->types, 21197f1cc26dSEd Tanous std::move(getChassisCb)); 212062598e31SEd Tanous BMCWEB_LOG_DEBUG("getChassisData exit"); 2121271584abSEd Tanous } 212208777fb0SLewanczyk, Dawid 2123413961deSRichard Marian Thomaiyar /** 212449c53ac9SJohnathan Mantey * @brief Find the requested sensorName in the list of all sensors supplied by 212549c53ac9SJohnathan Mantey * the chassis node 212649c53ac9SJohnathan Mantey * 212749c53ac9SJohnathan Mantey * @param sensorName The sensor name supplied in the PATCH request 212849c53ac9SJohnathan Mantey * @param sensorsList The list of sensors managed by the chassis node 212949c53ac9SJohnathan Mantey * @param sensorsModified The list of sensors that were found as a result of 213049c53ac9SJohnathan Mantey * repeated calls to this function 213149c53ac9SJohnathan Mantey */ 2132bd79bce8SPatrick Williams inline bool findSensorNameUsingSensorPath( 2133bd79bce8SPatrick Williams std::string_view sensorName, const std::set<std::string>& sensorsList, 2134fe04d49cSNan Zhou std::set<std::string>& sensorsModified) 213549c53ac9SJohnathan Mantey { 2136fe04d49cSNan Zhou for (const auto& chassisSensor : sensorsList) 213749c53ac9SJohnathan Mantey { 213828aa8de5SGeorge Liu sdbusplus::message::object_path path(chassisSensor); 2139b00dcc27SEd Tanous std::string thisSensorName = path.filename(); 214028aa8de5SGeorge Liu if (thisSensorName.empty()) 214149c53ac9SJohnathan Mantey { 214249c53ac9SJohnathan Mantey continue; 214349c53ac9SJohnathan Mantey } 214449c53ac9SJohnathan Mantey if (thisSensorName == sensorName) 214549c53ac9SJohnathan Mantey { 214649c53ac9SJohnathan Mantey sensorsModified.emplace(chassisSensor); 214749c53ac9SJohnathan Mantey return true; 214849c53ac9SJohnathan Mantey } 214949c53ac9SJohnathan Mantey } 215049c53ac9SJohnathan Mantey return false; 215149c53ac9SJohnathan Mantey } 215249c53ac9SJohnathan Mantey 215349c53ac9SJohnathan Mantey /** 2154413961deSRichard Marian Thomaiyar * @brief Entry point for overriding sensor values of given sensor 2155413961deSRichard Marian Thomaiyar * 21568d1b46d7Szhanghch05 * @param sensorAsyncResp response object 21574bb3dc34SCarol Wang * @param allCollections Collections extract from sensors' request patch info 2158413961deSRichard Marian Thomaiyar * @param chassisSubNode Chassis Node for which the query has to happen 2159413961deSRichard Marian Thomaiyar */ 216023a21a1cSEd Tanous inline void setSensorsOverride( 2161b5a76932SEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp, 21620885057cSEd Tanous std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>& 2163397fd61fSjayaprakash Mutyala allCollections) 2164413961deSRichard Marian Thomaiyar { 216562598e31SEd Tanous BMCWEB_LOG_INFO("setSensorsOverride for subNode{}", 216662598e31SEd Tanous sensorAsyncResp->chassisSubNode); 2167413961deSRichard Marian Thomaiyar 2168d02aad39SEd Tanous std::string_view propertyValueName; 2169f65af9e8SRichard Marian Thomaiyar std::unordered_map<std::string, std::pair<double, std::string>> overrideMap; 2170413961deSRichard Marian Thomaiyar std::string memberId; 2171543f4400SEd Tanous double value = 0.0; 2172f65af9e8SRichard Marian Thomaiyar for (auto& collectionItems : allCollections) 2173f65af9e8SRichard Marian Thomaiyar { 2174f65af9e8SRichard Marian Thomaiyar if (collectionItems.first == "Temperatures") 2175f65af9e8SRichard Marian Thomaiyar { 2176f65af9e8SRichard Marian Thomaiyar propertyValueName = "ReadingCelsius"; 2177f65af9e8SRichard Marian Thomaiyar } 2178f65af9e8SRichard Marian Thomaiyar else if (collectionItems.first == "Fans") 2179f65af9e8SRichard Marian Thomaiyar { 2180f65af9e8SRichard Marian Thomaiyar propertyValueName = "Reading"; 2181f65af9e8SRichard Marian Thomaiyar } 2182f65af9e8SRichard Marian Thomaiyar else 2183f65af9e8SRichard Marian Thomaiyar { 2184f65af9e8SRichard Marian Thomaiyar propertyValueName = "ReadingVolts"; 2185f65af9e8SRichard Marian Thomaiyar } 2186f65af9e8SRichard Marian Thomaiyar for (auto& item : collectionItems.second) 2187f65af9e8SRichard Marian Thomaiyar { 2188*afc474aeSMyung Bae if (!json_util::readJsonObject( // 2189*afc474aeSMyung Bae item, sensorAsyncResp->asyncResp->res, // 2190*afc474aeSMyung Bae "MemberId", memberId, // 2191*afc474aeSMyung Bae propertyValueName, value // 2192*afc474aeSMyung Bae )) 2193413961deSRichard Marian Thomaiyar { 2194413961deSRichard Marian Thomaiyar return; 2195413961deSRichard Marian Thomaiyar } 2196f65af9e8SRichard Marian Thomaiyar overrideMap.emplace(memberId, 2197f65af9e8SRichard Marian Thomaiyar std::make_pair(value, collectionItems.first)); 2198f65af9e8SRichard Marian Thomaiyar } 2199f65af9e8SRichard Marian Thomaiyar } 22004bb3dc34SCarol Wang 2201bd79bce8SPatrick Williams auto getChassisSensorListCb = [sensorAsyncResp, overrideMap, 2202bd79bce8SPatrick Williams propertyValueNameStr = 2203bd79bce8SPatrick Williams std::string(propertyValueName)]( 2204bd79bce8SPatrick Williams const std::shared_ptr< 2205bd79bce8SPatrick Williams std::set<std::string>>& sensorsList) { 220649c53ac9SJohnathan Mantey // Match sensor names in the PATCH request to those managed by the 220749c53ac9SJohnathan Mantey // chassis node 2208fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>> sensorNames = 2209fe04d49cSNan Zhou std::make_shared<std::set<std::string>>(); 2210f65af9e8SRichard Marian Thomaiyar for (const auto& item : overrideMap) 2211413961deSRichard Marian Thomaiyar { 2212f65af9e8SRichard Marian Thomaiyar const auto& sensor = item.first; 2213c71d6125SEd Tanous std::pair<std::string, std::string> sensorNameType = 22141516c21bSJanet Adkins redfish::sensor_utils::splitSensorNameAndType(sensor); 2215c71d6125SEd Tanous if (!findSensorNameUsingSensorPath(sensorNameType.second, 2216c71d6125SEd Tanous *sensorsList, *sensorNames)) 2217f65af9e8SRichard Marian Thomaiyar { 221862598e31SEd Tanous BMCWEB_LOG_INFO("Unable to find memberId {}", item.first); 22198d1b46d7Szhanghch05 messages::resourceNotFound(sensorAsyncResp->asyncResp->res, 2220f65af9e8SRichard Marian Thomaiyar item.second.second, item.first); 2221413961deSRichard Marian Thomaiyar return; 2222413961deSRichard Marian Thomaiyar } 2223f65af9e8SRichard Marian Thomaiyar } 2224413961deSRichard Marian Thomaiyar // Get the connection to which the memberId belongs 2225bd79bce8SPatrick Williams auto getObjectsWithConnectionCb = [sensorAsyncResp, overrideMap, 2226bd79bce8SPatrick Williams propertyValueNameStr]( 2227bd79bce8SPatrick Williams const std::set< 2228bd79bce8SPatrick Williams std::string>& /*connections*/, 2229bd79bce8SPatrick Williams const std::set<std::pair< 2230bd79bce8SPatrick Williams std::string, std::string>>& 2231413961deSRichard Marian Thomaiyar objectsWithConnection) { 2232f65af9e8SRichard Marian Thomaiyar if (objectsWithConnection.size() != overrideMap.size()) 2233413961deSRichard Marian Thomaiyar { 223462598e31SEd Tanous BMCWEB_LOG_INFO( 223562598e31SEd Tanous "Unable to find all objects with proper connection {} requested {}", 223662598e31SEd Tanous objectsWithConnection.size(), overrideMap.size()); 2237bd79bce8SPatrick Williams messages::resourceNotFound( 2238bd79bce8SPatrick Williams sensorAsyncResp->asyncResp->res, 22390c728b42SJanet Adkins sensorAsyncResp->chassisSubNode == sensors::thermalNodeStr 2240413961deSRichard Marian Thomaiyar ? "Temperatures" 2241413961deSRichard Marian Thomaiyar : "Voltages", 2242f65af9e8SRichard Marian Thomaiyar "Count"); 2243f65af9e8SRichard Marian Thomaiyar return; 2244f65af9e8SRichard Marian Thomaiyar } 2245f65af9e8SRichard Marian Thomaiyar for (const auto& item : objectsWithConnection) 2246f65af9e8SRichard Marian Thomaiyar { 224728aa8de5SGeorge Liu sdbusplus::message::object_path path(item.first); 224828aa8de5SGeorge Liu std::string sensorName = path.filename(); 224928aa8de5SGeorge Liu if (sensorName.empty()) 2250f65af9e8SRichard Marian Thomaiyar { 22514f277b54SJayaprakash Mutyala messages::internalError(sensorAsyncResp->asyncResp->res); 2252f65af9e8SRichard Marian Thomaiyar return; 2253f65af9e8SRichard Marian Thomaiyar } 22541516c21bSJanet Adkins std::string id = redfish::sensor_utils::getSensorId( 22551516c21bSJanet Adkins sensorName, path.parent_path().filename()); 2256f65af9e8SRichard Marian Thomaiyar 22573f5eb755SBan Feng const auto& iterator = overrideMap.find(id); 2258f65af9e8SRichard Marian Thomaiyar if (iterator == overrideMap.end()) 2259f65af9e8SRichard Marian Thomaiyar { 226062598e31SEd Tanous BMCWEB_LOG_INFO("Unable to find sensor object{}", 226162598e31SEd Tanous item.first); 22624f277b54SJayaprakash Mutyala messages::internalError(sensorAsyncResp->asyncResp->res); 2263413961deSRichard Marian Thomaiyar return; 2264413961deSRichard Marian Thomaiyar } 2265e93abac6SGinu George setDbusProperty(sensorAsyncResp->asyncResp, 2266e93abac6SGinu George propertyValueNameStr, item.second, item.first, 2267e93abac6SGinu George "xyz.openbmc_project.Sensor.Value", "Value", 2268d02aad39SEd Tanous iterator->second.first); 2269f65af9e8SRichard Marian Thomaiyar } 2270413961deSRichard Marian Thomaiyar }; 2271413961deSRichard Marian Thomaiyar // Get object with connection for the given sensor name 2272413961deSRichard Marian Thomaiyar getObjectsWithConnection(sensorAsyncResp, sensorNames, 2273413961deSRichard Marian Thomaiyar std::move(getObjectsWithConnectionCb)); 2274413961deSRichard Marian Thomaiyar }; 2275413961deSRichard Marian Thomaiyar // get full sensor list for the given chassisId and cross verify the sensor. 22767f1cc26dSEd Tanous getChassis(sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId, 22777f1cc26dSEd Tanous sensorAsyncResp->chassisSubNode, sensorAsyncResp->types, 22787f1cc26dSEd Tanous std::move(getChassisSensorListCb)); 2279413961deSRichard Marian Thomaiyar } 2280413961deSRichard Marian Thomaiyar 2281a0ec28b6SAdrian Ambrożewicz /** 2282a0ec28b6SAdrian Ambrożewicz * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus 2283a0ec28b6SAdrian Ambrożewicz * path of the sensor. 2284a0ec28b6SAdrian Ambrożewicz * 2285a0ec28b6SAdrian Ambrożewicz * Function builds valid Redfish response for sensor query of given chassis and 2286a0ec28b6SAdrian Ambrożewicz * node. It then builds metadata about Redfish<->D-Bus correlations and provides 2287a0ec28b6SAdrian Ambrożewicz * it to caller in a callback. 2288a0ec28b6SAdrian Ambrożewicz * 2289a0ec28b6SAdrian Ambrożewicz * @param chassis Chassis for which retrieval should be performed 2290c9563608SJanet Adkins * @param node Node (group) of sensors. See sensor_utils::node for supported 2291c9563608SJanet Adkins * values 2292a0ec28b6SAdrian Ambrożewicz * @param mapComplete Callback to be called with retrieval result 2293a0ec28b6SAdrian Ambrożewicz */ 2294931edc79SEd Tanous template <typename Callback> 2295bd79bce8SPatrick Williams inline void retrieveUriToDbusMap( 2296bd79bce8SPatrick Williams const std::string& chassis, const std::string& node, Callback&& mapComplete) 2297a0ec28b6SAdrian Ambrożewicz { 229802da7c5aSEd Tanous decltype(sensors::paths)::const_iterator pathIt = 229902da7c5aSEd Tanous std::find_if(sensors::paths.cbegin(), sensors::paths.cend(), 230002da7c5aSEd Tanous [&node](auto&& val) { return val.first == node; }); 230102da7c5aSEd Tanous if (pathIt == sensors::paths.cend()) 2302a0ec28b6SAdrian Ambrożewicz { 230362598e31SEd Tanous BMCWEB_LOG_ERROR("Wrong node provided : {}", node); 23046804b5c8SEd Tanous std::map<std::string, std::string> noop; 23056804b5c8SEd Tanous mapComplete(boost::beast::http::status::bad_request, noop); 2306a0ec28b6SAdrian Ambrożewicz return; 2307a0ec28b6SAdrian Ambrożewicz } 2308d51e072fSKrzysztof Grobelny 230972374eb7SNan Zhou auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); 2310bd79bce8SPatrick Williams auto callback = 2311bd79bce8SPatrick Williams [asyncResp, mapCompleteCb = std::forward<Callback>(mapComplete)]( 2312a0ec28b6SAdrian Ambrożewicz const boost::beast::http::status status, 2313fe04d49cSNan Zhou const std::map<std::string, std::string>& uriToDbus) { 2314fe04d49cSNan Zhou mapCompleteCb(status, uriToDbus); 2315fe04d49cSNan Zhou }; 2316a0ec28b6SAdrian Ambrożewicz 2317a0ec28b6SAdrian Ambrożewicz auto resp = std::make_shared<SensorsAsyncResp>( 2318d51e072fSKrzysztof Grobelny asyncResp, chassis, pathIt->second, node, std::move(callback)); 2319a0ec28b6SAdrian Ambrożewicz getChassisData(resp); 2320a0ec28b6SAdrian Ambrożewicz } 2321a0ec28b6SAdrian Ambrożewicz 2322bacb2162SNan Zhou namespace sensors 2323bacb2162SNan Zhou { 2324928fefb9SNan Zhou 2325bacb2162SNan Zhou inline void getChassisCallback( 2326c1d019a6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2327c1d019a6SEd Tanous std::string_view chassisId, std::string_view chassisSubNode, 2328fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& sensorNames) 2329bacb2162SNan Zhou { 233062598e31SEd Tanous BMCWEB_LOG_DEBUG("getChassisCallback enter "); 2331bacb2162SNan Zhou 2332c1d019a6SEd Tanous nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"]; 2333c1d019a6SEd Tanous for (const std::string& sensor : *sensorNames) 2334bacb2162SNan Zhou { 233562598e31SEd Tanous BMCWEB_LOG_DEBUG("Adding sensor: {}", sensor); 2336bacb2162SNan Zhou 2337bacb2162SNan Zhou sdbusplus::message::object_path path(sensor); 2338bacb2162SNan Zhou std::string sensorName = path.filename(); 2339bacb2162SNan Zhou if (sensorName.empty()) 2340bacb2162SNan Zhou { 234162598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid sensor path: {}", sensor); 2342c1d019a6SEd Tanous messages::internalError(asyncResp->res); 2343bacb2162SNan Zhou return; 2344bacb2162SNan Zhou } 2345c1d019a6SEd Tanous std::string type = path.parent_path().filename(); 23461516c21bSJanet Adkins std::string id = redfish::sensor_utils::getSensorId(sensorName, type); 2347c1d019a6SEd Tanous 23481476687dSEd Tanous nlohmann::json::object_t member; 2349ef4c65b7SEd Tanous member["@odata.id"] = boost::urls::format( 2350ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/{}/{}", chassisId, chassisSubNode, id); 2351c1d019a6SEd Tanous 2352b2ba3072SPatrick Williams entriesArray.emplace_back(std::move(member)); 2353bacb2162SNan Zhou } 2354bacb2162SNan Zhou 2355c1d019a6SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 235662598e31SEd Tanous BMCWEB_LOG_DEBUG("getChassisCallback exit"); 2357bacb2162SNan Zhou } 2358e6bd846dSNan Zhou 2359ac106bf6SEd Tanous inline void handleSensorCollectionGet( 2360ac106bf6SEd Tanous App& app, const crow::Request& req, 2361ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2362de167a6fSNan Zhou const std::string& chassisId) 2363de167a6fSNan Zhou { 2364de167a6fSNan Zhou query_param::QueryCapabilities capabilities = { 2365de167a6fSNan Zhou .canDelegateExpandLevel = 1, 2366de167a6fSNan Zhou }; 2367de167a6fSNan Zhou query_param::Query delegatedQuery; 2368ac106bf6SEd Tanous if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp, 2369de167a6fSNan Zhou delegatedQuery, capabilities)) 2370de167a6fSNan Zhou { 2371de167a6fSNan Zhou return; 2372de167a6fSNan Zhou } 2373de167a6fSNan Zhou 2374de167a6fSNan Zhou if (delegatedQuery.expandType != query_param::ExpandType::None) 2375de167a6fSNan Zhou { 2376de167a6fSNan Zhou // we perform efficient expand. 2377ac106bf6SEd Tanous auto sensorsAsyncResp = std::make_shared<SensorsAsyncResp>( 2378ac106bf6SEd Tanous asyncResp, chassisId, sensors::dbus::sensorPaths, 23790c728b42SJanet Adkins sensors::sensorsNodeStr, 2380de167a6fSNan Zhou /*efficientExpand=*/true); 2381ac106bf6SEd Tanous getChassisData(sensorsAsyncResp); 2382de167a6fSNan Zhou 238362598e31SEd Tanous BMCWEB_LOG_DEBUG( 238462598e31SEd Tanous "SensorCollection doGet exit via efficient expand handler"); 2385de167a6fSNan Zhou return; 23860bad320cSEd Tanous } 2387de167a6fSNan Zhou 2388de167a6fSNan Zhou // We get all sensors as hyperlinkes in the chassis (this 2389de167a6fSNan Zhou // implies we reply on the default query parameters handler) 23900c728b42SJanet Adkins getChassis(asyncResp, chassisId, sensors::sensorsNodeStr, dbus::sensorPaths, 2391ac106bf6SEd Tanous std::bind_front(sensors::getChassisCallback, asyncResp, 23920c728b42SJanet Adkins chassisId, sensors::sensorsNodeStr)); 2393c1d019a6SEd Tanous } 23947f1cc26dSEd Tanous 2395c1d019a6SEd Tanous inline void 2396c1d019a6SEd Tanous getSensorFromDbus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2397c1d019a6SEd Tanous const std::string& sensorPath, 2398c1d019a6SEd Tanous const ::dbus::utility::MapperGetObject& mapperResponse) 2399c1d019a6SEd Tanous { 2400c1d019a6SEd Tanous if (mapperResponse.size() != 1) 2401c1d019a6SEd Tanous { 2402c1d019a6SEd Tanous messages::internalError(asyncResp->res); 2403c1d019a6SEd Tanous return; 2404c1d019a6SEd Tanous } 2405c1d019a6SEd Tanous const auto& valueIface = *mapperResponse.begin(); 2406c1d019a6SEd Tanous const std::string& connectionName = valueIface.first; 240762598e31SEd Tanous BMCWEB_LOG_DEBUG("Looking up {}", connectionName); 240862598e31SEd Tanous BMCWEB_LOG_DEBUG("Path {}", sensorPath); 2409c1343bf6SKrzysztof Grobelny 2410c1343bf6SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 2411c1343bf6SKrzysztof Grobelny *crow::connections::systemBus, connectionName, sensorPath, "", 2412c1d019a6SEd Tanous [asyncResp, 24135e7e2dc5SEd Tanous sensorPath](const boost::system::error_code& ec, 2414c1d019a6SEd Tanous const ::dbus::utility::DBusPropertiesMap& valuesDict) { 2415c1d019a6SEd Tanous if (ec) 2416c1d019a6SEd Tanous { 2417c1d019a6SEd Tanous messages::internalError(asyncResp->res); 2418c1d019a6SEd Tanous return; 2419c1d019a6SEd Tanous } 2420c1d019a6SEd Tanous sdbusplus::message::object_path path(sensorPath); 2421c1d019a6SEd Tanous std::string name = path.filename(); 2422c1d019a6SEd Tanous path = path.parent_path(); 2423c1d019a6SEd Tanous std::string type = path.filename(); 2424c9563608SJanet Adkins sensor_utils::objectPropertiesToJson( 24250c728b42SJanet Adkins name, type, sensor_utils::ChassisSubNode::sensorsNode, 24260c728b42SJanet Adkins valuesDict, asyncResp->res.jsonValue, nullptr); 2427c1343bf6SKrzysztof Grobelny }); 2428de167a6fSNan Zhou } 2429de167a6fSNan Zhou 2430e6bd846dSNan Zhou inline void handleSensorGet(App& app, const crow::Request& req, 2431c1d019a6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2432677bb756SEd Tanous const std::string& chassisId, 2433c1d019a6SEd Tanous const std::string& sensorId) 2434e6bd846dSNan Zhou { 2435c1d019a6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2436e6bd846dSNan Zhou { 2437e6bd846dSNan Zhou return; 2438e6bd846dSNan Zhou } 2439c71d6125SEd Tanous std::pair<std::string, std::string> nameType = 24401516c21bSJanet Adkins redfish::sensor_utils::splitSensorNameAndType(sensorId); 2441c71d6125SEd Tanous if (nameType.first.empty() || nameType.second.empty()) 2442c1d019a6SEd Tanous { 2443c1d019a6SEd Tanous messages::resourceNotFound(asyncResp->res, sensorId, "Sensor"); 2444c1d019a6SEd Tanous return; 2445c1d019a6SEd Tanous } 2446c71d6125SEd Tanous 2447ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 2448ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/Sensors/{}", chassisId, sensorId); 2449c1d019a6SEd Tanous 245062598e31SEd Tanous BMCWEB_LOG_DEBUG("Sensor doGet enter"); 2451e6bd846dSNan Zhou 24522b73119cSGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 2453e6bd846dSNan Zhou "xyz.openbmc_project.Sensor.Value"}; 2454c71d6125SEd Tanous std::string sensorPath = "/xyz/openbmc_project/sensors/" + nameType.first + 2455c71d6125SEd Tanous '/' + nameType.second; 2456e6bd846dSNan Zhou // Get a list of all of the sensors that implement Sensor.Value 2457e6bd846dSNan Zhou // and get the path and service name associated with the sensor 24582b73119cSGeorge Liu ::dbus::utility::getDbusObject( 24592b73119cSGeorge Liu sensorPath, interfaces, 2460aec0ec30SMyung Bae [asyncResp, sensorId, 24612b73119cSGeorge Liu sensorPath](const boost::system::error_code& ec, 2462c1d019a6SEd Tanous const ::dbus::utility::MapperGetObject& subtree) { 246362598e31SEd Tanous BMCWEB_LOG_DEBUG("respHandler1 enter"); 2464aec0ec30SMyung Bae if (ec == boost::system::errc::io_error) 2465aec0ec30SMyung Bae { 246662598e31SEd Tanous BMCWEB_LOG_WARNING("Sensor not found from getSensorPaths"); 2467aec0ec30SMyung Bae messages::resourceNotFound(asyncResp->res, sensorId, "Sensor"); 2468aec0ec30SMyung Bae return; 2469aec0ec30SMyung Bae } 2470e6bd846dSNan Zhou if (ec) 2471e6bd846dSNan Zhou { 2472c1d019a6SEd Tanous messages::internalError(asyncResp->res); 247362598e31SEd Tanous BMCWEB_LOG_ERROR( 247462598e31SEd Tanous "Sensor getSensorPaths resp_handler: Dbus error {}", ec); 2475e6bd846dSNan Zhou return; 2476e6bd846dSNan Zhou } 2477c1d019a6SEd Tanous getSensorFromDbus(asyncResp, sensorPath, subtree); 247862598e31SEd Tanous BMCWEB_LOG_DEBUG("respHandler1 exit"); 24792b73119cSGeorge Liu }); 2480e6bd846dSNan Zhou } 2481e6bd846dSNan Zhou 2482bacb2162SNan Zhou } // namespace sensors 2483bacb2162SNan Zhou 24847e860f15SJohn Edward Broadbent inline void requestRoutesSensorCollection(App& app) 248595a3ecadSAnthony Wilson { 24867e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/") 2487ed398213SEd Tanous .privileges(redfish::privileges::getSensorCollection) 2488002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2489de167a6fSNan Zhou std::bind_front(sensors::handleSensorCollectionGet, std::ref(app))); 249095a3ecadSAnthony Wilson } 249195a3ecadSAnthony Wilson 24927e860f15SJohn Edward Broadbent inline void requestRoutesSensor(App& app) 249395a3ecadSAnthony Wilson { 24947e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/") 2495ed398213SEd Tanous .privileges(redfish::privileges::getSensor) 2496002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2497e6bd846dSNan Zhou std::bind_front(sensors::handleSensorGet, std::ref(app))); 249895a3ecadSAnthony Wilson } 249995a3ecadSAnthony Wilson 250008777fb0SLewanczyk, Dawid } // namespace redfish 2501