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 } 558*deae6a78SEd Tanous dbus::utility::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 1378*deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 1379*deae6a78SEd Tanous ledConnection, ledPath, "xyz.openbmc_project.Led.Physical", "State", 13801e1e598dSJonathan Doman std::move(respHandler)); 1381d500549bSAnthony Wilson } 1382d500549bSAnthony Wilson 138362598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryLedData exit"); 1384d500549bSAnthony Wilson } 1385d500549bSAnthony Wilson 1386d500549bSAnthony Wilson /** 1387d500549bSAnthony Wilson * @brief Gets LED data for LEDs associated with given inventory items. 1388d500549bSAnthony Wilson * 1389d500549bSAnthony Wilson * Gets the D-Bus connections (services) that provide LED data for the LEDs 1390d500549bSAnthony Wilson * associated with the specified inventory items. Then gets the LED data from 1391d500549bSAnthony Wilson * each connection and stores it in the inventory item. 1392d500549bSAnthony Wilson * 1393d500549bSAnthony Wilson * This data is later used to provide sensor property values in the JSON 1394d500549bSAnthony Wilson * response. 1395d500549bSAnthony Wilson * 1396d500549bSAnthony Wilson * Finds the LED data asynchronously. Invokes callback when information has 1397d500549bSAnthony Wilson * been obtained. 1398d500549bSAnthony Wilson * 1399d500549bSAnthony Wilson * The callback must have the following signature: 1400d500549bSAnthony Wilson * @code 140142cbe538SGunnar Mills * callback() 1402d500549bSAnthony Wilson * @endcode 1403d500549bSAnthony Wilson * 1404d500549bSAnthony Wilson * @param sensorsAsyncResp Pointer to object holding response data. 1405d500549bSAnthony Wilson * @param inventoryItems D-Bus inventory items associated with sensors. 1406d500549bSAnthony Wilson * @param callback Callback to invoke when inventory items have been obtained. 1407d500549bSAnthony Wilson */ 1408d500549bSAnthony Wilson template <typename Callback> 1409d500549bSAnthony Wilson void getInventoryLeds( 1410d500549bSAnthony Wilson std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 1411d500549bSAnthony Wilson std::shared_ptr<std::vector<InventoryItem>> inventoryItems, 1412d500549bSAnthony Wilson Callback&& callback) 1413d500549bSAnthony Wilson { 141462598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryLeds enter"); 1415d500549bSAnthony Wilson 1416d500549bSAnthony Wilson const std::string path = "/xyz/openbmc_project"; 1417e99073f5SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 1418d500549bSAnthony Wilson "xyz.openbmc_project.Led.Physical"}; 1419d500549bSAnthony Wilson 1420e99073f5SGeorge Liu // Make call to ObjectMapper to find all inventory items 1421e99073f5SGeorge Liu dbus::utility::getSubTree( 1422e99073f5SGeorge Liu path, 0, interfaces, 14238cb2c024SEd Tanous [callback = std::forward<Callback>(callback), sensorsAsyncResp, 1424002d39b4SEd Tanous inventoryItems]( 1425e99073f5SGeorge Liu const boost::system::error_code& ec, 14264e0d8789SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) mutable { 1427e99073f5SGeorge Liu // Response handler for parsing output from GetSubTree 142862598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryLeds respHandler enter"); 1429d500549bSAnthony Wilson if (ec) 1430d500549bSAnthony Wilson { 14318d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 1432bd79bce8SPatrick Williams BMCWEB_LOG_ERROR("getInventoryLeds respHandler DBus error {}", 1433bd79bce8SPatrick Williams ec); 1434d500549bSAnthony Wilson return; 1435d500549bSAnthony Wilson } 1436d500549bSAnthony Wilson 1437d500549bSAnthony Wilson // Build map of LED object paths to connections 1438fe04d49cSNan Zhou std::shared_ptr<std::map<std::string, std::string>> ledConnections = 1439fe04d49cSNan Zhou std::make_shared<std::map<std::string, std::string>>(); 1440d500549bSAnthony Wilson 1441d500549bSAnthony Wilson // Loop through objects from GetSubTree 1442bd79bce8SPatrick Williams for (const std::pair<std::string, 1443bd79bce8SPatrick Williams std::vector<std::pair< 1444bd79bce8SPatrick Williams std::string, std::vector<std::string>>>>& 1445d500549bSAnthony Wilson object : subtree) 1446d500549bSAnthony Wilson { 1447bd79bce8SPatrick Williams // Check if object path is LED for one of the specified 1448bd79bce8SPatrick Williams // inventory items 1449d500549bSAnthony Wilson const std::string& ledPath = object.first; 1450bd79bce8SPatrick Williams if (findInventoryItemForLed(*inventoryItems, ledPath) != 1451bd79bce8SPatrick Williams nullptr) 1452d500549bSAnthony Wilson { 1453d500549bSAnthony Wilson // Add mapping from ledPath to connection 1454bd79bce8SPatrick Williams const std::string& connection = 1455bd79bce8SPatrick Williams object.second.begin()->first; 1456d500549bSAnthony Wilson (*ledConnections)[ledPath] = connection; 1457bd79bce8SPatrick Williams BMCWEB_LOG_DEBUG("Added mapping {} -> {}", ledPath, 1458bd79bce8SPatrick Williams connection); 1459d500549bSAnthony Wilson } 1460d500549bSAnthony Wilson } 1461d500549bSAnthony Wilson 1462bd79bce8SPatrick Williams getInventoryLedData(sensorsAsyncResp, inventoryItems, 1463bd79bce8SPatrick Williams ledConnections, std::move(callback)); 146462598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryLeds respHandler exit"); 1465e99073f5SGeorge Liu }); 146662598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryLeds exit"); 1467d500549bSAnthony Wilson } 1468d500549bSAnthony Wilson 1469d500549bSAnthony Wilson /** 147042cbe538SGunnar Mills * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent 147142cbe538SGunnar Mills * 147242cbe538SGunnar Mills * Uses the specified connections (services) (currently assumes just one) to 147342cbe538SGunnar Mills * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in 147442cbe538SGunnar Mills * the inventoryItems vector. Only stores data in Power Supply inventoryItems. 147542cbe538SGunnar Mills * 147642cbe538SGunnar Mills * This data is later used to provide sensor property values in the JSON 147742cbe538SGunnar Mills * response. 147842cbe538SGunnar Mills * 147942cbe538SGunnar Mills * Finds the Power Supply Attributes data asynchronously. Invokes callback 148042cbe538SGunnar Mills * when data has been obtained. 148142cbe538SGunnar Mills * 148242cbe538SGunnar Mills * The callback must have the following signature: 148342cbe538SGunnar Mills * @code 148442cbe538SGunnar Mills * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems) 148542cbe538SGunnar Mills * @endcode 148642cbe538SGunnar Mills * 148742cbe538SGunnar Mills * @param sensorsAsyncResp Pointer to object holding response data. 148842cbe538SGunnar Mills * @param inventoryItems D-Bus inventory items associated with sensors. 148942cbe538SGunnar Mills * @param psAttributesConnections Connections that provide data for the Power 149042cbe538SGunnar Mills * Supply Attributes 149142cbe538SGunnar Mills * @param callback Callback to invoke when data has been obtained. 149242cbe538SGunnar Mills */ 149342cbe538SGunnar Mills template <typename Callback> 149442cbe538SGunnar Mills void getPowerSupplyAttributesData( 1495b5a76932SEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp, 149642cbe538SGunnar Mills std::shared_ptr<std::vector<InventoryItem>> inventoryItems, 1497fe04d49cSNan Zhou const std::map<std::string, std::string>& psAttributesConnections, 149842cbe538SGunnar Mills Callback&& callback) 149942cbe538SGunnar Mills { 150062598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData enter"); 150142cbe538SGunnar Mills 150242cbe538SGunnar Mills if (psAttributesConnections.empty()) 150342cbe538SGunnar Mills { 150462598e31SEd Tanous BMCWEB_LOG_DEBUG("Can't find PowerSupplyAttributes, no connections!"); 150542cbe538SGunnar Mills callback(inventoryItems); 150642cbe538SGunnar Mills return; 150742cbe538SGunnar Mills } 150842cbe538SGunnar Mills 150942cbe538SGunnar Mills // Assuming just one connection (service) for now 1510fe04d49cSNan Zhou auto it = psAttributesConnections.begin(); 151142cbe538SGunnar Mills 151242cbe538SGunnar Mills const std::string& psAttributesPath = (*it).first; 151342cbe538SGunnar Mills const std::string& psAttributesConnection = (*it).second; 151442cbe538SGunnar Mills 151542cbe538SGunnar Mills // Response handler for Get DeratingFactor property 15165a39f77aSPatrick Williams auto respHandler = [sensorsAsyncResp, inventoryItems, 15178cb2c024SEd Tanous callback = std::forward<Callback>(callback)]( 15185a39f77aSPatrick Williams const boost::system::error_code& ec, 15194e0d8789SEd Tanous uint32_t value) mutable { 152062598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler enter"); 152142cbe538SGunnar Mills if (ec) 152242cbe538SGunnar Mills { 152362598e31SEd Tanous BMCWEB_LOG_ERROR( 152462598e31SEd Tanous "getPowerSupplyAttributesData respHandler DBus error {}", ec); 15258d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 152642cbe538SGunnar Mills return; 152742cbe538SGunnar Mills } 152842cbe538SGunnar Mills 152962598e31SEd Tanous BMCWEB_LOG_DEBUG("PS EfficiencyPercent value: {}", value); 153042cbe538SGunnar Mills // Store value in Power Supply Inventory Items 153142cbe538SGunnar Mills for (InventoryItem& inventoryItem : *inventoryItems) 153242cbe538SGunnar Mills { 153355f79e6fSEd Tanous if (inventoryItem.isPowerSupply) 153442cbe538SGunnar Mills { 153542cbe538SGunnar Mills inventoryItem.powerSupplyEfficiencyPercent = 15361e1e598dSJonathan Doman static_cast<int>(value); 153742cbe538SGunnar Mills } 153842cbe538SGunnar Mills } 153942cbe538SGunnar Mills 154062598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler exit"); 154142cbe538SGunnar Mills callback(inventoryItems); 154242cbe538SGunnar Mills }; 154342cbe538SGunnar Mills 154442cbe538SGunnar Mills // Get the DeratingFactor property for the PowerSupplyAttributes 154542cbe538SGunnar Mills // Currently only property on the interface/only one we care about 1546*deae6a78SEd Tanous dbus::utility::getProperty<uint32_t>( 1547*deae6a78SEd Tanous psAttributesConnection, psAttributesPath, 15481e1e598dSJonathan Doman "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor", 15491e1e598dSJonathan Doman std::move(respHandler)); 155042cbe538SGunnar Mills 155162598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData exit"); 155242cbe538SGunnar Mills } 155342cbe538SGunnar Mills 155442cbe538SGunnar Mills /** 155542cbe538SGunnar Mills * @brief Gets the Power Supply Attributes such as EfficiencyPercent 155642cbe538SGunnar Mills * 155742cbe538SGunnar Mills * Gets the D-Bus connection (service) that provides Power Supply Attributes 155842cbe538SGunnar Mills * data. Then gets the Power Supply Attributes data from the connection 155942cbe538SGunnar Mills * (currently just assumes 1 connection) and stores the data in the inventory 156042cbe538SGunnar Mills * item. 156142cbe538SGunnar Mills * 156242cbe538SGunnar Mills * This data is later used to provide sensor property values in the JSON 156342cbe538SGunnar Mills * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish. 156442cbe538SGunnar Mills * 156542cbe538SGunnar Mills * Finds the Power Supply Attributes data asynchronously. Invokes callback 156642cbe538SGunnar Mills * when information has been obtained. 156742cbe538SGunnar Mills * 156842cbe538SGunnar Mills * The callback must have the following signature: 156942cbe538SGunnar Mills * @code 157042cbe538SGunnar Mills * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems) 157142cbe538SGunnar Mills * @endcode 157242cbe538SGunnar Mills * 157342cbe538SGunnar Mills * @param sensorsAsyncResp Pointer to object holding response data. 157442cbe538SGunnar Mills * @param inventoryItems D-Bus inventory items associated with sensors. 157542cbe538SGunnar Mills * @param callback Callback to invoke when data has been obtained. 157642cbe538SGunnar Mills */ 157742cbe538SGunnar Mills template <typename Callback> 157842cbe538SGunnar Mills void getPowerSupplyAttributes( 157942cbe538SGunnar Mills std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 158042cbe538SGunnar Mills std::shared_ptr<std::vector<InventoryItem>> inventoryItems, 158142cbe538SGunnar Mills Callback&& callback) 158242cbe538SGunnar Mills { 158362598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributes enter"); 158442cbe538SGunnar Mills 158542cbe538SGunnar Mills // Only need the power supply attributes when the Power Schema 15860c728b42SJanet Adkins if (sensorsAsyncResp->chassisSubNode != sensors::powerNodeStr) 158742cbe538SGunnar Mills { 158862598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit since not Power"); 158942cbe538SGunnar Mills callback(inventoryItems); 159042cbe538SGunnar Mills return; 159142cbe538SGunnar Mills } 159242cbe538SGunnar Mills 1593e99073f5SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 159442cbe538SGunnar Mills "xyz.openbmc_project.Control.PowerSupplyAttributes"}; 159542cbe538SGunnar Mills 1596e99073f5SGeorge Liu // Make call to ObjectMapper to find the PowerSupplyAttributes service 1597e99073f5SGeorge Liu dbus::utility::getSubTree( 1598e99073f5SGeorge Liu "/xyz/openbmc_project", 0, interfaces, 15998cb2c024SEd Tanous [callback = std::forward<Callback>(callback), sensorsAsyncResp, 1600b9d36b47SEd Tanous inventoryItems]( 1601e99073f5SGeorge Liu const boost::system::error_code& ec, 16024e0d8789SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) mutable { 1603e99073f5SGeorge Liu // Response handler for parsing output from GetSubTree 160462598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler enter"); 160542cbe538SGunnar Mills if (ec) 160642cbe538SGunnar Mills { 16078d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 160862598e31SEd Tanous BMCWEB_LOG_ERROR( 160962598e31SEd Tanous "getPowerSupplyAttributes respHandler DBus error {}", ec); 161042cbe538SGunnar Mills return; 161142cbe538SGunnar Mills } 161226f6976fSEd Tanous if (subtree.empty()) 161342cbe538SGunnar Mills { 161462598e31SEd Tanous BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!"); 161542cbe538SGunnar Mills callback(inventoryItems); 161642cbe538SGunnar Mills return; 161742cbe538SGunnar Mills } 161842cbe538SGunnar Mills 161942cbe538SGunnar Mills // Currently we only support 1 power supply attribute, use this for 162042cbe538SGunnar Mills // all the power supplies. Build map of object path to connection. 162142cbe538SGunnar Mills // Assume just 1 connection and 1 path for now. 1622fe04d49cSNan Zhou std::map<std::string, std::string> psAttributesConnections; 162342cbe538SGunnar Mills 162442cbe538SGunnar Mills if (subtree[0].first.empty() || subtree[0].second.empty()) 162542cbe538SGunnar Mills { 162662598e31SEd Tanous BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!"); 162742cbe538SGunnar Mills callback(inventoryItems); 162842cbe538SGunnar Mills return; 162942cbe538SGunnar Mills } 163042cbe538SGunnar Mills 163142cbe538SGunnar Mills const std::string& psAttributesPath = subtree[0].first; 163242cbe538SGunnar Mills const std::string& connection = subtree[0].second.begin()->first; 163342cbe538SGunnar Mills 163442cbe538SGunnar Mills if (connection.empty()) 163542cbe538SGunnar Mills { 163662598e31SEd Tanous BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!"); 163742cbe538SGunnar Mills callback(inventoryItems); 163842cbe538SGunnar Mills return; 163942cbe538SGunnar Mills } 164042cbe538SGunnar Mills 164142cbe538SGunnar Mills psAttributesConnections[psAttributesPath] = connection; 164262598e31SEd Tanous BMCWEB_LOG_DEBUG("Added mapping {} -> {}", psAttributesPath, 164362598e31SEd Tanous connection); 164442cbe538SGunnar Mills 164542cbe538SGunnar Mills getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems, 164642cbe538SGunnar Mills psAttributesConnections, 164742cbe538SGunnar Mills std::move(callback)); 164862598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler exit"); 1649e99073f5SGeorge Liu }); 165062598e31SEd Tanous BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit"); 165142cbe538SGunnar Mills } 165242cbe538SGunnar Mills 165342cbe538SGunnar Mills /** 1654adc4f0dbSShawn McCarney * @brief Gets inventory items associated with sensors. 16558fb49dd6SShawn McCarney * 16568fb49dd6SShawn McCarney * Finds the inventory items that are associated with the specified sensors. 1657adc4f0dbSShawn McCarney * Then gets D-Bus data for the inventory items, such as presence and VPD. 16588fb49dd6SShawn McCarney * 1659adc4f0dbSShawn McCarney * This data is later used to provide sensor property values in the JSON 1660adc4f0dbSShawn McCarney * response. 16618fb49dd6SShawn McCarney * 1662adc4f0dbSShawn McCarney * Finds the inventory items asynchronously. Invokes callback when the 1663adc4f0dbSShawn McCarney * inventory items have been obtained. 1664adc4f0dbSShawn McCarney * 1665adc4f0dbSShawn McCarney * The callback must have the following signature: 1666adc4f0dbSShawn McCarney * @code 1667adc4f0dbSShawn McCarney * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems) 1668adc4f0dbSShawn McCarney * @endcode 16698fb49dd6SShawn McCarney * 16708fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 16718fb49dd6SShawn McCarney * @param sensorNames All sensors within the current chassis. 16728fb49dd6SShawn McCarney * implements ObjectManager. 1673adc4f0dbSShawn McCarney * @param callback Callback to invoke when inventory items have been obtained. 16748fb49dd6SShawn McCarney */ 1675adc4f0dbSShawn McCarney template <typename Callback> 16764ff0f1f4SEd Tanous inline void 1677d0090733SEd Tanous getInventoryItems(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 1678fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>> sensorNames, 1679adc4f0dbSShawn McCarney Callback&& callback) 16808fb49dd6SShawn McCarney { 168162598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItems enter"); 1682adc4f0dbSShawn McCarney auto getInventoryItemAssociationsCb = 16838cb2c024SEd Tanous [sensorsAsyncResp, callback = std::forward<Callback>(callback)]( 16844e0d8789SEd Tanous std::shared_ptr<std::vector<InventoryItem>> 16854e0d8789SEd Tanous inventoryItems) mutable { 168662598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb enter"); 16878fb49dd6SShawn McCarney auto getInventoryItemsConnectionsCb = 1688d0090733SEd Tanous [sensorsAsyncResp, inventoryItems, 16894e0d8789SEd Tanous callback = std::forward<Callback>(callback)]( 16904e0d8789SEd Tanous std::shared_ptr<std::set<std::string>> 16914e0d8789SEd Tanous invConnections) mutable { 169262598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb enter"); 1693bd79bce8SPatrick Williams auto getInventoryItemsDataCb = 1694bd79bce8SPatrick Williams [sensorsAsyncResp, inventoryItems, 16954e0d8789SEd Tanous callback = 16964e0d8789SEd Tanous std::forward<Callback>(callback)]() mutable { 169762598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsDataCb enter"); 169842cbe538SGunnar Mills 1699bd79bce8SPatrick Williams auto getInventoryLedsCb = 1700bd79bce8SPatrick Williams [sensorsAsyncResp, inventoryItems, 17014e0d8789SEd Tanous callback = std::forward<Callback>( 17024e0d8789SEd Tanous callback)]() mutable { 1703bd79bce8SPatrick Williams BMCWEB_LOG_DEBUG( 1704bd79bce8SPatrick Williams "getInventoryLedsCb enter"); 1705bd79bce8SPatrick Williams // Find Power Supply Attributes and get the 1706bd79bce8SPatrick Williams // data 1707bd79bce8SPatrick Williams getPowerSupplyAttributes( 1708bd79bce8SPatrick Williams sensorsAsyncResp, inventoryItems, 170942cbe538SGunnar Mills std::move(callback)); 171062598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryLedsCb exit"); 171142cbe538SGunnar Mills }; 171242cbe538SGunnar Mills 1713d500549bSAnthony Wilson // Find led connections and get the data 1714d500549bSAnthony Wilson getInventoryLeds(sensorsAsyncResp, inventoryItems, 171542cbe538SGunnar Mills std::move(getInventoryLedsCb)); 171662598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsDataCb exit"); 1717d500549bSAnthony Wilson }; 17188fb49dd6SShawn McCarney 1719adc4f0dbSShawn McCarney // Get inventory item data from connections 1720adc4f0dbSShawn McCarney getInventoryItemsData(sensorsAsyncResp, inventoryItems, 1721d0090733SEd Tanous invConnections, 1722d500549bSAnthony Wilson std::move(getInventoryItemsDataCb)); 172362598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb exit"); 17248fb49dd6SShawn McCarney }; 17258fb49dd6SShawn McCarney 1726adc4f0dbSShawn McCarney // Get connections that provide inventory item data 1727bd79bce8SPatrick Williams getInventoryItemsConnections( 1728bd79bce8SPatrick Williams sensorsAsyncResp, inventoryItems, 17298fb49dd6SShawn McCarney std::move(getInventoryItemsConnectionsCb)); 173062598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb exit"); 17318fb49dd6SShawn McCarney }; 17328fb49dd6SShawn McCarney 1733adc4f0dbSShawn McCarney // Get associations from sensors to inventory items 1734d0090733SEd Tanous getInventoryItemAssociations(sensorsAsyncResp, sensorNames, 1735adc4f0dbSShawn McCarney std::move(getInventoryItemAssociationsCb)); 173662598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItems exit"); 1737adc4f0dbSShawn McCarney } 1738adc4f0dbSShawn McCarney 1739adc4f0dbSShawn McCarney /** 1740adc4f0dbSShawn McCarney * @brief Returns JSON PowerSupply object for the specified inventory item. 1741adc4f0dbSShawn McCarney * 1742adc4f0dbSShawn McCarney * Searches for a JSON PowerSupply object that matches the specified inventory 1743adc4f0dbSShawn McCarney * item. If one is not found, a new PowerSupply object is added to the JSON 1744adc4f0dbSShawn McCarney * array. 1745adc4f0dbSShawn McCarney * 1746adc4f0dbSShawn McCarney * Multiple sensors are often associated with one power supply inventory item. 1747adc4f0dbSShawn McCarney * As a result, multiple sensor values are stored in one JSON PowerSupply 1748adc4f0dbSShawn McCarney * object. 1749adc4f0dbSShawn McCarney * 1750adc4f0dbSShawn McCarney * @param powerSupplyArray JSON array containing Redfish PowerSupply objects. 1751adc4f0dbSShawn McCarney * @param inventoryItem Inventory item for the power supply. 1752adc4f0dbSShawn McCarney * @param chassisId Chassis that contains the power supply. 1753adc4f0dbSShawn McCarney * @return JSON PowerSupply object for the specified inventory item. 1754adc4f0dbSShawn McCarney */ 175523a21a1cSEd Tanous inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray, 1756adc4f0dbSShawn McCarney const InventoryItem& inventoryItem, 1757adc4f0dbSShawn McCarney const std::string& chassisId) 1758adc4f0dbSShawn McCarney { 175918f8f608SEd Tanous std::string nameS; 17606f4bd290SAlexander Hansen nameS.resize(inventoryItem.name.size()); 176118f8f608SEd Tanous std::ranges::replace_copy(inventoryItem.name, nameS.begin(), '_', ' '); 1762adc4f0dbSShawn McCarney // Check if matching PowerSupply object already exists in JSON array 1763adc4f0dbSShawn McCarney for (nlohmann::json& powerSupply : powerSupplyArray) 1764adc4f0dbSShawn McCarney { 176518f8f608SEd Tanous nlohmann::json::iterator nameIt = powerSupply.find("Name"); 176618f8f608SEd Tanous if (nameIt == powerSupply.end()) 176718f8f608SEd Tanous { 176818f8f608SEd Tanous continue; 176918f8f608SEd Tanous } 177018f8f608SEd Tanous const std::string* name = nameIt->get_ptr<std::string*>(); 177118f8f608SEd Tanous if (name == nullptr) 177218f8f608SEd Tanous { 177318f8f608SEd Tanous continue; 177418f8f608SEd Tanous } 177518f8f608SEd Tanous if (nameS == *name) 1776adc4f0dbSShawn McCarney { 1777adc4f0dbSShawn McCarney return powerSupply; 1778adc4f0dbSShawn McCarney } 1779adc4f0dbSShawn McCarney } 1780adc4f0dbSShawn McCarney 1781adc4f0dbSShawn McCarney // Add new PowerSupply object to JSON array 1782adc4f0dbSShawn McCarney powerSupplyArray.push_back({}); 1783adc4f0dbSShawn McCarney nlohmann::json& powerSupply = powerSupplyArray.back(); 1784bd79bce8SPatrick Williams boost::urls::url url = 1785bd79bce8SPatrick Williams boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId); 1786eddfc437SWilly Tu url.set_fragment(("/PowerSupplies"_json_pointer).to_string()); 1787eddfc437SWilly Tu powerSupply["@odata.id"] = std::move(url); 178818f8f608SEd Tanous std::string escaped; 17896f4bd290SAlexander Hansen escaped.resize(inventoryItem.name.size()); 179018f8f608SEd Tanous std::ranges::replace_copy(inventoryItem.name, escaped.begin(), '_', ' '); 179118f8f608SEd Tanous powerSupply["Name"] = std::move(escaped); 1792adc4f0dbSShawn McCarney powerSupply["Manufacturer"] = inventoryItem.manufacturer; 1793adc4f0dbSShawn McCarney powerSupply["Model"] = inventoryItem.model; 1794adc4f0dbSShawn McCarney powerSupply["PartNumber"] = inventoryItem.partNumber; 1795adc4f0dbSShawn McCarney powerSupply["SerialNumber"] = inventoryItem.serialNumber; 1796c9563608SJanet Adkins sensor_utils::setLedState(powerSupply, &inventoryItem); 1797adc4f0dbSShawn McCarney 179842cbe538SGunnar Mills if (inventoryItem.powerSupplyEfficiencyPercent >= 0) 179942cbe538SGunnar Mills { 180042cbe538SGunnar Mills powerSupply["EfficiencyPercent"] = 180142cbe538SGunnar Mills inventoryItem.powerSupplyEfficiencyPercent; 180242cbe538SGunnar Mills } 180342cbe538SGunnar Mills 1804c9563608SJanet Adkins powerSupply["Status"]["State"] = 1805c9563608SJanet Adkins sensor_utils::getState(&inventoryItem, true); 1806adc4f0dbSShawn McCarney const char* health = inventoryItem.isFunctional ? "OK" : "Critical"; 1807adc4f0dbSShawn McCarney powerSupply["Status"]["Health"] = health; 1808adc4f0dbSShawn McCarney 1809adc4f0dbSShawn McCarney return powerSupply; 18108fb49dd6SShawn McCarney } 18118fb49dd6SShawn McCarney 18128fb49dd6SShawn McCarney /** 1813de629b6eSShawn McCarney * @brief Gets the values of the specified sensors. 1814de629b6eSShawn McCarney * 1815de629b6eSShawn McCarney * Stores the results as JSON in the SensorsAsyncResp. 1816de629b6eSShawn McCarney * 1817de629b6eSShawn McCarney * Gets the sensor values asynchronously. Stores the results later when the 1818de629b6eSShawn McCarney * information has been obtained. 1819de629b6eSShawn McCarney * 1820adc4f0dbSShawn McCarney * The sensorNames set contains all requested sensors for the current chassis. 1821de629b6eSShawn McCarney * 1822de629b6eSShawn McCarney * To minimize the number of DBus calls, the DBus method 1823de629b6eSShawn McCarney * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the 1824de629b6eSShawn McCarney * values of all sensors provided by a connection (service). 1825de629b6eSShawn McCarney * 1826de629b6eSShawn McCarney * The connections set contains all the connections that provide sensor values. 1827de629b6eSShawn McCarney * 1828adc4f0dbSShawn McCarney * The InventoryItem vector contains D-Bus inventory items associated with the 1829adc4f0dbSShawn McCarney * sensors. Inventory item data is needed for some Redfish sensor properties. 1830adc4f0dbSShawn McCarney * 1831de629b6eSShawn McCarney * @param SensorsAsyncResp Pointer to object holding response data. 1832adc4f0dbSShawn McCarney * @param sensorNames All requested sensors within the current chassis. 1833de629b6eSShawn McCarney * @param connections Connections that provide sensor values. 1834de629b6eSShawn McCarney * implements ObjectManager. 1835adc4f0dbSShawn McCarney * @param inventoryItems Inventory items associated with the sensors. 1836de629b6eSShawn McCarney */ 183723a21a1cSEd Tanous inline void getSensorData( 183881ce609eSEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp, 1839fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& sensorNames, 1840fe04d49cSNan Zhou const std::set<std::string>& connections, 1841b5a76932SEd Tanous const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems) 1842de629b6eSShawn McCarney { 184362598e31SEd Tanous BMCWEB_LOG_DEBUG("getSensorData enter"); 1844de629b6eSShawn McCarney // Get managed objects from all services exposing sensors 1845de629b6eSShawn McCarney for (const std::string& connection : connections) 1846de629b6eSShawn McCarney { 18475eb468daSGeorge Liu sdbusplus::message::object_path sensorPath( 18485eb468daSGeorge Liu "/xyz/openbmc_project/sensors"); 18495eb468daSGeorge Liu dbus::utility::getManagedObjects( 18505eb468daSGeorge Liu connection, sensorPath, 1851002d39b4SEd Tanous [sensorsAsyncResp, sensorNames, 18525e7e2dc5SEd Tanous inventoryItems](const boost::system::error_code& ec, 185302cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 185462598e31SEd Tanous BMCWEB_LOG_DEBUG("getManagedObjectsCb enter"); 1855de629b6eSShawn McCarney if (ec) 1856de629b6eSShawn McCarney { 185762598e31SEd Tanous BMCWEB_LOG_ERROR("getManagedObjectsCb DBUS error: {}", ec); 18588d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 1859de629b6eSShawn McCarney return; 1860de629b6eSShawn McCarney } 18610c728b42SJanet Adkins auto chassisSubNode = sensor_utils::chassisSubNodeFromString( 18620c728b42SJanet Adkins sensorsAsyncResp->chassisSubNode); 1863de629b6eSShawn McCarney // Go through all objects and update response with sensor data 1864de629b6eSShawn McCarney for (const auto& objDictEntry : resp) 1865de629b6eSShawn McCarney { 1866de629b6eSShawn McCarney const std::string& objPath = 1867de629b6eSShawn McCarney static_cast<const std::string&>(objDictEntry.first); 186862598e31SEd Tanous BMCWEB_LOG_DEBUG("getManagedObjectsCb parsing object {}", 186962598e31SEd Tanous objPath); 1870de629b6eSShawn McCarney 1871de629b6eSShawn McCarney std::vector<std::string> split; 1872de629b6eSShawn McCarney // Reserve space for 1873de629b6eSShawn McCarney // /xyz/openbmc_project/sensors/<name>/<subname> 1874de629b6eSShawn McCarney split.reserve(6); 187550ebd4afSEd Tanous // NOLINTNEXTLINE 187650ebd4afSEd Tanous bmcweb::split(split, objPath, '/'); 1877de629b6eSShawn McCarney if (split.size() < 6) 1878de629b6eSShawn McCarney { 187962598e31SEd Tanous BMCWEB_LOG_ERROR("Got path that isn't long enough {}", 188062598e31SEd Tanous objPath); 1881de629b6eSShawn McCarney continue; 1882de629b6eSShawn McCarney } 188350ebd4afSEd Tanous // These indexes aren't intuitive, as split puts an empty 1884de629b6eSShawn McCarney // string at the beginning 1885de629b6eSShawn McCarney const std::string& sensorType = split[4]; 1886de629b6eSShawn McCarney const std::string& sensorName = split[5]; 188762598e31SEd Tanous BMCWEB_LOG_DEBUG("sensorName {} sensorType {}", sensorName, 188862598e31SEd Tanous sensorType); 188949c53ac9SJohnathan Mantey if (sensorNames->find(objPath) == sensorNames->end()) 1890de629b6eSShawn McCarney { 189162598e31SEd Tanous BMCWEB_LOG_DEBUG("{} not in sensor list ", sensorName); 1892de629b6eSShawn McCarney continue; 1893de629b6eSShawn McCarney } 1894de629b6eSShawn McCarney 1895adc4f0dbSShawn McCarney // Find inventory item (if any) associated with sensor 1896adc4f0dbSShawn McCarney InventoryItem* inventoryItem = 1897adc4f0dbSShawn McCarney findInventoryItemForSensor(inventoryItems, objPath); 1898adc4f0dbSShawn McCarney 189995a3ecadSAnthony Wilson const std::string& sensorSchema = 190081ce609eSEd Tanous sensorsAsyncResp->chassisSubNode; 190195a3ecadSAnthony Wilson 190295a3ecadSAnthony Wilson nlohmann::json* sensorJson = nullptr; 190395a3ecadSAnthony Wilson 19040c728b42SJanet Adkins if (sensorSchema == sensors::sensorsNodeStr && 1905928fefb9SNan Zhou !sensorsAsyncResp->efficientExpand) 190695a3ecadSAnthony Wilson { 19071516c21bSJanet Adkins std::string sensorId = 19081516c21bSJanet Adkins redfish::sensor_utils::getSensorId(sensorName, 19091516c21bSJanet Adkins sensorType); 1910c1d019a6SEd Tanous 1911bd79bce8SPatrick Williams sensorsAsyncResp->asyncResp->res 1912bd79bce8SPatrick Williams .jsonValue["@odata.id"] = boost::urls::format( 1913bd79bce8SPatrick Williams "/redfish/v1/Chassis/{}/{}/{}", 1914c1d019a6SEd Tanous sensorsAsyncResp->chassisId, 1915bd79bce8SPatrick Williams sensorsAsyncResp->chassisSubNode, sensorId); 1916bd79bce8SPatrick Williams sensorJson = 1917bd79bce8SPatrick Williams &(sensorsAsyncResp->asyncResp->res.jsonValue); 191895a3ecadSAnthony Wilson } 191995a3ecadSAnthony Wilson else 192095a3ecadSAnthony Wilson { 1921271584abSEd Tanous std::string fieldName; 1922928fefb9SNan Zhou if (sensorsAsyncResp->efficientExpand) 1923928fefb9SNan Zhou { 1924928fefb9SNan Zhou fieldName = "Members"; 1925928fefb9SNan Zhou } 1926928fefb9SNan Zhou else if (sensorType == "temperature") 1927de629b6eSShawn McCarney { 1928de629b6eSShawn McCarney fieldName = "Temperatures"; 1929de629b6eSShawn McCarney } 1930bd79bce8SPatrick Williams else if (sensorType == "fan" || 1931bd79bce8SPatrick Williams sensorType == "fan_tach" || 1932de629b6eSShawn McCarney sensorType == "fan_pwm") 1933de629b6eSShawn McCarney { 1934de629b6eSShawn McCarney fieldName = "Fans"; 1935de629b6eSShawn McCarney } 1936de629b6eSShawn McCarney else if (sensorType == "voltage") 1937de629b6eSShawn McCarney { 1938de629b6eSShawn McCarney fieldName = "Voltages"; 1939de629b6eSShawn McCarney } 1940de629b6eSShawn McCarney else if (sensorType == "power") 1941de629b6eSShawn McCarney { 194255f79e6fSEd Tanous if (sensorName == "total_power") 1943028f7ebcSEddie James { 1944028f7ebcSEddie James fieldName = "PowerControl"; 1945028f7ebcSEddie James } 1946adc4f0dbSShawn McCarney else if ((inventoryItem != nullptr) && 1947adc4f0dbSShawn McCarney (inventoryItem->isPowerSupply)) 1948028f7ebcSEddie James { 1949de629b6eSShawn McCarney fieldName = "PowerSupplies"; 1950de629b6eSShawn McCarney } 1951adc4f0dbSShawn McCarney else 1952adc4f0dbSShawn McCarney { 1953adc4f0dbSShawn McCarney // Other power sensors are in SensorCollection 1954adc4f0dbSShawn McCarney continue; 1955adc4f0dbSShawn McCarney } 1956028f7ebcSEddie James } 1957de629b6eSShawn McCarney else 1958de629b6eSShawn McCarney { 1959bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 1960bd79bce8SPatrick Williams "Unsure how to handle sensorType {}", 196162598e31SEd Tanous sensorType); 1962de629b6eSShawn McCarney continue; 1963de629b6eSShawn McCarney } 1964de629b6eSShawn McCarney 1965de629b6eSShawn McCarney nlohmann::json& tempArray = 1966bd79bce8SPatrick Williams sensorsAsyncResp->asyncResp->res 1967bd79bce8SPatrick Williams .jsonValue[fieldName]; 1968adc4f0dbSShawn McCarney if (fieldName == "PowerControl") 196949c53ac9SJohnathan Mantey { 1970adc4f0dbSShawn McCarney if (tempArray.empty()) 19717ab06f49SGunnar Mills { 197295a3ecadSAnthony Wilson // Put multiple "sensors" into a single 197395a3ecadSAnthony Wilson // PowerControl. Follows MemberId naming and 197495a3ecadSAnthony Wilson // naming in power.hpp. 19751476687dSEd Tanous nlohmann::json::object_t power; 1976ef4c65b7SEd Tanous boost::urls::url url = boost::urls::format( 1977ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/{}", 1978eddfc437SWilly Tu sensorsAsyncResp->chassisId, 1979eddfc437SWilly Tu sensorsAsyncResp->chassisSubNode); 1980bd79bce8SPatrick Williams url.set_fragment( 1981bd79bce8SPatrick Williams (""_json_pointer / fieldName / "0") 1982eddfc437SWilly Tu .to_string()); 1983eddfc437SWilly Tu power["@odata.id"] = std::move(url); 1984b2ba3072SPatrick Williams tempArray.emplace_back(std::move(power)); 1985adc4f0dbSShawn McCarney } 1986adc4f0dbSShawn McCarney sensorJson = &(tempArray.back()); 1987adc4f0dbSShawn McCarney } 1988adc4f0dbSShawn McCarney else if (fieldName == "PowerSupplies") 1989adc4f0dbSShawn McCarney { 1990adc4f0dbSShawn McCarney if (inventoryItem != nullptr) 1991adc4f0dbSShawn McCarney { 1992bd79bce8SPatrick Williams sensorJson = &(getPowerSupply( 1993bd79bce8SPatrick Williams tempArray, *inventoryItem, 199481ce609eSEd Tanous sensorsAsyncResp->chassisId)); 1995adc4f0dbSShawn McCarney } 199649c53ac9SJohnathan Mantey } 1997928fefb9SNan Zhou else if (fieldName == "Members") 1998928fefb9SNan Zhou { 19991516c21bSJanet Adkins std::string sensorId = 20001516c21bSJanet Adkins redfish::sensor_utils::getSensorId(sensorName, 20011516c21bSJanet Adkins sensorType); 2002677bb756SEd Tanous 20031476687dSEd Tanous nlohmann::json::object_t member; 2004ef4c65b7SEd Tanous member["@odata.id"] = boost::urls::format( 2005ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/{}/{}", 2006677bb756SEd Tanous sensorsAsyncResp->chassisId, 2007677bb756SEd Tanous sensorsAsyncResp->chassisSubNode, sensorId); 2008b2ba3072SPatrick Williams tempArray.emplace_back(std::move(member)); 2009928fefb9SNan Zhou sensorJson = &(tempArray.back()); 2010928fefb9SNan Zhou } 201149c53ac9SJohnathan Mantey else 201249c53ac9SJohnathan Mantey { 20131476687dSEd Tanous nlohmann::json::object_t member; 2014ef4c65b7SEd Tanous boost::urls::url url = boost::urls::format( 2015ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/{}", 2016eddfc437SWilly Tu sensorsAsyncResp->chassisId, 2017eddfc437SWilly Tu sensorsAsyncResp->chassisSubNode); 2018eddfc437SWilly Tu url.set_fragment( 2019eddfc437SWilly Tu (""_json_pointer / fieldName).to_string()); 2020eddfc437SWilly Tu member["@odata.id"] = std::move(url); 2021b2ba3072SPatrick Williams tempArray.emplace_back(std::move(member)); 2022adc4f0dbSShawn McCarney sensorJson = &(tempArray.back()); 202349c53ac9SJohnathan Mantey } 202495a3ecadSAnthony Wilson } 2025de629b6eSShawn McCarney 2026adc4f0dbSShawn McCarney if (sensorJson != nullptr) 2027adc4f0dbSShawn McCarney { 20280c728b42SJanet Adkins objectInterfacesToJson( 20290c728b42SJanet Adkins sensorName, sensorType, chassisSubNode, 20300c728b42SJanet Adkins objDictEntry.second, *sensorJson, inventoryItem); 20311d7c0054SEd Tanous 20321d7c0054SEd Tanous std::string path = "/xyz/openbmc_project/sensors/"; 20331d7c0054SEd Tanous path += sensorType; 20341d7c0054SEd Tanous path += "/"; 20351d7c0054SEd Tanous path += sensorName; 2036c1d019a6SEd Tanous sensorsAsyncResp->addMetadata(*sensorJson, path); 2037adc4f0dbSShawn McCarney } 2038de629b6eSShawn McCarney } 203981ce609eSEd Tanous if (sensorsAsyncResp.use_count() == 1) 204049c53ac9SJohnathan Mantey { 204181ce609eSEd Tanous sortJSONResponse(sensorsAsyncResp); 20420c728b42SJanet Adkins if (chassisSubNode == 20430c728b42SJanet Adkins sensor_utils::ChassisSubNode::sensorsNode && 2044928fefb9SNan Zhou sensorsAsyncResp->efficientExpand) 2045928fefb9SNan Zhou { 2046928fefb9SNan Zhou sensorsAsyncResp->asyncResp->res 2047928fefb9SNan Zhou .jsonValue["Members@odata.count"] = 2048bd79bce8SPatrick Williams sensorsAsyncResp->asyncResp->res 2049bd79bce8SPatrick Williams .jsonValue["Members"] 2050928fefb9SNan Zhou .size(); 2051928fefb9SNan Zhou } 20520c728b42SJanet Adkins else if (chassisSubNode == 20530c728b42SJanet Adkins sensor_utils::ChassisSubNode::thermalNode) 20548bd25ccdSJames Feist { 205581ce609eSEd Tanous populateFanRedundancy(sensorsAsyncResp); 20568bd25ccdSJames Feist } 205749c53ac9SJohnathan Mantey } 205862598e31SEd Tanous BMCWEB_LOG_DEBUG("getManagedObjectsCb exit"); 20595eb468daSGeorge Liu }); 206023a21a1cSEd Tanous } 206162598e31SEd Tanous BMCWEB_LOG_DEBUG("getSensorData exit"); 2062de629b6eSShawn McCarney } 2063de629b6eSShawn McCarney 2064fe04d49cSNan Zhou inline void 2065fe04d49cSNan Zhou processSensorList(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp, 2066fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& sensorNames) 20671abe55efSEd Tanous { 2068fe04d49cSNan Zhou auto getConnectionCb = [sensorsAsyncResp, sensorNames]( 2069fe04d49cSNan Zhou const std::set<std::string>& connections) { 207062598e31SEd Tanous BMCWEB_LOG_DEBUG("getConnectionCb enter"); 2071adc4f0dbSShawn McCarney auto getInventoryItemsCb = 2072bd79bce8SPatrick Williams [sensorsAsyncResp, sensorNames, connections]( 2073bd79bce8SPatrick Williams const std::shared_ptr<std::vector<InventoryItem>>& 20744e0d8789SEd Tanous inventoryItems) mutable { 207562598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsCb enter"); 207649c53ac9SJohnathan Mantey // Get sensor data and store results in JSON 2077002d39b4SEd Tanous getSensorData(sensorsAsyncResp, sensorNames, connections, 2078d0090733SEd Tanous inventoryItems); 207962598e31SEd Tanous BMCWEB_LOG_DEBUG("getInventoryItemsCb exit"); 2080adc4f0dbSShawn McCarney }; 2081adc4f0dbSShawn McCarney 2082adc4f0dbSShawn McCarney // Get inventory items associated with sensors 2083d0090733SEd Tanous getInventoryItems(sensorsAsyncResp, sensorNames, 2084adc4f0dbSShawn McCarney std::move(getInventoryItemsCb)); 2085adc4f0dbSShawn McCarney 208662598e31SEd Tanous BMCWEB_LOG_DEBUG("getConnectionCb exit"); 208708777fb0SLewanczyk, Dawid }; 2088de629b6eSShawn McCarney 2089de629b6eSShawn McCarney // Get set of connections that provide sensor values 209081ce609eSEd Tanous getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb)); 209195a3ecadSAnthony Wilson } 209295a3ecadSAnthony Wilson 209395a3ecadSAnthony Wilson /** 209495a3ecadSAnthony Wilson * @brief Entry point for retrieving sensors data related to requested 209595a3ecadSAnthony Wilson * chassis. 209695a3ecadSAnthony Wilson * @param SensorsAsyncResp Pointer to object holding response data 209795a3ecadSAnthony Wilson */ 2098b5a76932SEd Tanous inline void 209981ce609eSEd Tanous getChassisData(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp) 210095a3ecadSAnthony Wilson { 210162598e31SEd Tanous BMCWEB_LOG_DEBUG("getChassisData enter"); 210295a3ecadSAnthony Wilson auto getChassisCb = 210381ce609eSEd Tanous [sensorsAsyncResp]( 2104fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& sensorNames) { 210562598e31SEd Tanous BMCWEB_LOG_DEBUG("getChassisCb enter"); 210681ce609eSEd Tanous processSensorList(sensorsAsyncResp, sensorNames); 210762598e31SEd Tanous BMCWEB_LOG_DEBUG("getChassisCb exit"); 210808777fb0SLewanczyk, Dawid }; 2109928fefb9SNan Zhou // SensorCollection doesn't contain the Redundancy property 21100c728b42SJanet Adkins if (sensorsAsyncResp->chassisSubNode != sensors::sensorsNodeStr) 2111928fefb9SNan Zhou { 21128d1b46d7Szhanghch05 sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] = 21138d1b46d7Szhanghch05 nlohmann::json::array(); 2114928fefb9SNan Zhou } 211526f03899SShawn McCarney // Get set of sensors in chassis 21167f1cc26dSEd Tanous getChassis(sensorsAsyncResp->asyncResp, sensorsAsyncResp->chassisId, 21177f1cc26dSEd Tanous sensorsAsyncResp->chassisSubNode, sensorsAsyncResp->types, 21187f1cc26dSEd Tanous std::move(getChassisCb)); 211962598e31SEd Tanous BMCWEB_LOG_DEBUG("getChassisData exit"); 2120271584abSEd Tanous } 212108777fb0SLewanczyk, Dawid 2122413961deSRichard Marian Thomaiyar /** 212349c53ac9SJohnathan Mantey * @brief Find the requested sensorName in the list of all sensors supplied by 212449c53ac9SJohnathan Mantey * the chassis node 212549c53ac9SJohnathan Mantey * 212649c53ac9SJohnathan Mantey * @param sensorName The sensor name supplied in the PATCH request 212749c53ac9SJohnathan Mantey * @param sensorsList The list of sensors managed by the chassis node 212849c53ac9SJohnathan Mantey * @param sensorsModified The list of sensors that were found as a result of 212949c53ac9SJohnathan Mantey * repeated calls to this function 213049c53ac9SJohnathan Mantey */ 2131bd79bce8SPatrick Williams inline bool findSensorNameUsingSensorPath( 2132bd79bce8SPatrick Williams std::string_view sensorName, const std::set<std::string>& sensorsList, 2133fe04d49cSNan Zhou std::set<std::string>& sensorsModified) 213449c53ac9SJohnathan Mantey { 2135fe04d49cSNan Zhou for (const auto& chassisSensor : sensorsList) 213649c53ac9SJohnathan Mantey { 213728aa8de5SGeorge Liu sdbusplus::message::object_path path(chassisSensor); 2138b00dcc27SEd Tanous std::string thisSensorName = path.filename(); 213928aa8de5SGeorge Liu if (thisSensorName.empty()) 214049c53ac9SJohnathan Mantey { 214149c53ac9SJohnathan Mantey continue; 214249c53ac9SJohnathan Mantey } 214349c53ac9SJohnathan Mantey if (thisSensorName == sensorName) 214449c53ac9SJohnathan Mantey { 214549c53ac9SJohnathan Mantey sensorsModified.emplace(chassisSensor); 214649c53ac9SJohnathan Mantey return true; 214749c53ac9SJohnathan Mantey } 214849c53ac9SJohnathan Mantey } 214949c53ac9SJohnathan Mantey return false; 215049c53ac9SJohnathan Mantey } 215149c53ac9SJohnathan Mantey 215249c53ac9SJohnathan Mantey /** 2153413961deSRichard Marian Thomaiyar * @brief Entry point for overriding sensor values of given sensor 2154413961deSRichard Marian Thomaiyar * 21558d1b46d7Szhanghch05 * @param sensorAsyncResp response object 21564bb3dc34SCarol Wang * @param allCollections Collections extract from sensors' request patch info 2157413961deSRichard Marian Thomaiyar * @param chassisSubNode Chassis Node for which the query has to happen 2158413961deSRichard Marian Thomaiyar */ 215923a21a1cSEd Tanous inline void setSensorsOverride( 2160b5a76932SEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp, 21610885057cSEd Tanous std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>& 2162397fd61fSjayaprakash Mutyala allCollections) 2163413961deSRichard Marian Thomaiyar { 216462598e31SEd Tanous BMCWEB_LOG_INFO("setSensorsOverride for subNode{}", 216562598e31SEd Tanous sensorAsyncResp->chassisSubNode); 2166413961deSRichard Marian Thomaiyar 2167d02aad39SEd Tanous std::string_view propertyValueName; 2168f65af9e8SRichard Marian Thomaiyar std::unordered_map<std::string, std::pair<double, std::string>> overrideMap; 2169413961deSRichard Marian Thomaiyar std::string memberId; 2170543f4400SEd Tanous double value = 0.0; 2171f65af9e8SRichard Marian Thomaiyar for (auto& collectionItems : allCollections) 2172f65af9e8SRichard Marian Thomaiyar { 2173f65af9e8SRichard Marian Thomaiyar if (collectionItems.first == "Temperatures") 2174f65af9e8SRichard Marian Thomaiyar { 2175f65af9e8SRichard Marian Thomaiyar propertyValueName = "ReadingCelsius"; 2176f65af9e8SRichard Marian Thomaiyar } 2177f65af9e8SRichard Marian Thomaiyar else if (collectionItems.first == "Fans") 2178f65af9e8SRichard Marian Thomaiyar { 2179f65af9e8SRichard Marian Thomaiyar propertyValueName = "Reading"; 2180f65af9e8SRichard Marian Thomaiyar } 2181f65af9e8SRichard Marian Thomaiyar else 2182f65af9e8SRichard Marian Thomaiyar { 2183f65af9e8SRichard Marian Thomaiyar propertyValueName = "ReadingVolts"; 2184f65af9e8SRichard Marian Thomaiyar } 2185f65af9e8SRichard Marian Thomaiyar for (auto& item : collectionItems.second) 2186f65af9e8SRichard Marian Thomaiyar { 2187afc474aeSMyung Bae if (!json_util::readJsonObject( // 2188afc474aeSMyung Bae item, sensorAsyncResp->asyncResp->res, // 2189afc474aeSMyung Bae "MemberId", memberId, // 2190afc474aeSMyung Bae propertyValueName, value // 2191afc474aeSMyung Bae )) 2192413961deSRichard Marian Thomaiyar { 2193413961deSRichard Marian Thomaiyar return; 2194413961deSRichard Marian Thomaiyar } 2195f65af9e8SRichard Marian Thomaiyar overrideMap.emplace(memberId, 2196f65af9e8SRichard Marian Thomaiyar std::make_pair(value, collectionItems.first)); 2197f65af9e8SRichard Marian Thomaiyar } 2198f65af9e8SRichard Marian Thomaiyar } 21994bb3dc34SCarol Wang 2200bd79bce8SPatrick Williams auto getChassisSensorListCb = [sensorAsyncResp, overrideMap, 2201bd79bce8SPatrick Williams propertyValueNameStr = 2202bd79bce8SPatrick Williams std::string(propertyValueName)]( 2203bd79bce8SPatrick Williams const std::shared_ptr< 2204bd79bce8SPatrick Williams std::set<std::string>>& sensorsList) { 220549c53ac9SJohnathan Mantey // Match sensor names in the PATCH request to those managed by the 220649c53ac9SJohnathan Mantey // chassis node 2207fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>> sensorNames = 2208fe04d49cSNan Zhou std::make_shared<std::set<std::string>>(); 2209f65af9e8SRichard Marian Thomaiyar for (const auto& item : overrideMap) 2210413961deSRichard Marian Thomaiyar { 2211f65af9e8SRichard Marian Thomaiyar const auto& sensor = item.first; 2212c71d6125SEd Tanous std::pair<std::string, std::string> sensorNameType = 22131516c21bSJanet Adkins redfish::sensor_utils::splitSensorNameAndType(sensor); 2214c71d6125SEd Tanous if (!findSensorNameUsingSensorPath(sensorNameType.second, 2215c71d6125SEd Tanous *sensorsList, *sensorNames)) 2216f65af9e8SRichard Marian Thomaiyar { 221762598e31SEd Tanous BMCWEB_LOG_INFO("Unable to find memberId {}", item.first); 22188d1b46d7Szhanghch05 messages::resourceNotFound(sensorAsyncResp->asyncResp->res, 2219f65af9e8SRichard Marian Thomaiyar item.second.second, item.first); 2220413961deSRichard Marian Thomaiyar return; 2221413961deSRichard Marian Thomaiyar } 2222f65af9e8SRichard Marian Thomaiyar } 2223413961deSRichard Marian Thomaiyar // Get the connection to which the memberId belongs 2224bd79bce8SPatrick Williams auto getObjectsWithConnectionCb = [sensorAsyncResp, overrideMap, 2225bd79bce8SPatrick Williams propertyValueNameStr]( 2226bd79bce8SPatrick Williams const std::set< 2227bd79bce8SPatrick Williams std::string>& /*connections*/, 2228bd79bce8SPatrick Williams const std::set<std::pair< 2229bd79bce8SPatrick Williams std::string, std::string>>& 2230413961deSRichard Marian Thomaiyar objectsWithConnection) { 2231f65af9e8SRichard Marian Thomaiyar if (objectsWithConnection.size() != overrideMap.size()) 2232413961deSRichard Marian Thomaiyar { 223362598e31SEd Tanous BMCWEB_LOG_INFO( 223462598e31SEd Tanous "Unable to find all objects with proper connection {} requested {}", 223562598e31SEd Tanous objectsWithConnection.size(), overrideMap.size()); 2236bd79bce8SPatrick Williams messages::resourceNotFound( 2237bd79bce8SPatrick Williams sensorAsyncResp->asyncResp->res, 22380c728b42SJanet Adkins sensorAsyncResp->chassisSubNode == sensors::thermalNodeStr 2239413961deSRichard Marian Thomaiyar ? "Temperatures" 2240413961deSRichard Marian Thomaiyar : "Voltages", 2241f65af9e8SRichard Marian Thomaiyar "Count"); 2242f65af9e8SRichard Marian Thomaiyar return; 2243f65af9e8SRichard Marian Thomaiyar } 2244f65af9e8SRichard Marian Thomaiyar for (const auto& item : objectsWithConnection) 2245f65af9e8SRichard Marian Thomaiyar { 224628aa8de5SGeorge Liu sdbusplus::message::object_path path(item.first); 224728aa8de5SGeorge Liu std::string sensorName = path.filename(); 224828aa8de5SGeorge Liu if (sensorName.empty()) 2249f65af9e8SRichard Marian Thomaiyar { 22504f277b54SJayaprakash Mutyala messages::internalError(sensorAsyncResp->asyncResp->res); 2251f65af9e8SRichard Marian Thomaiyar return; 2252f65af9e8SRichard Marian Thomaiyar } 22531516c21bSJanet Adkins std::string id = redfish::sensor_utils::getSensorId( 22541516c21bSJanet Adkins sensorName, path.parent_path().filename()); 2255f65af9e8SRichard Marian Thomaiyar 22563f5eb755SBan Feng const auto& iterator = overrideMap.find(id); 2257f65af9e8SRichard Marian Thomaiyar if (iterator == overrideMap.end()) 2258f65af9e8SRichard Marian Thomaiyar { 225962598e31SEd Tanous BMCWEB_LOG_INFO("Unable to find sensor object{}", 226062598e31SEd Tanous item.first); 22614f277b54SJayaprakash Mutyala messages::internalError(sensorAsyncResp->asyncResp->res); 2262413961deSRichard Marian Thomaiyar return; 2263413961deSRichard Marian Thomaiyar } 2264e93abac6SGinu George setDbusProperty(sensorAsyncResp->asyncResp, 2265e93abac6SGinu George propertyValueNameStr, item.second, item.first, 2266e93abac6SGinu George "xyz.openbmc_project.Sensor.Value", "Value", 2267d02aad39SEd Tanous iterator->second.first); 2268f65af9e8SRichard Marian Thomaiyar } 2269413961deSRichard Marian Thomaiyar }; 2270413961deSRichard Marian Thomaiyar // Get object with connection for the given sensor name 2271413961deSRichard Marian Thomaiyar getObjectsWithConnection(sensorAsyncResp, sensorNames, 2272413961deSRichard Marian Thomaiyar std::move(getObjectsWithConnectionCb)); 2273413961deSRichard Marian Thomaiyar }; 2274413961deSRichard Marian Thomaiyar // get full sensor list for the given chassisId and cross verify the sensor. 22757f1cc26dSEd Tanous getChassis(sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId, 22767f1cc26dSEd Tanous sensorAsyncResp->chassisSubNode, sensorAsyncResp->types, 22777f1cc26dSEd Tanous std::move(getChassisSensorListCb)); 2278413961deSRichard Marian Thomaiyar } 2279413961deSRichard Marian Thomaiyar 2280a0ec28b6SAdrian Ambrożewicz /** 2281a0ec28b6SAdrian Ambrożewicz * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus 2282a0ec28b6SAdrian Ambrożewicz * path of the sensor. 2283a0ec28b6SAdrian Ambrożewicz * 2284a0ec28b6SAdrian Ambrożewicz * Function builds valid Redfish response for sensor query of given chassis and 2285a0ec28b6SAdrian Ambrożewicz * node. It then builds metadata about Redfish<->D-Bus correlations and provides 2286a0ec28b6SAdrian Ambrożewicz * it to caller in a callback. 2287a0ec28b6SAdrian Ambrożewicz * 2288a0ec28b6SAdrian Ambrożewicz * @param chassis Chassis for which retrieval should be performed 2289c9563608SJanet Adkins * @param node Node (group) of sensors. See sensor_utils::node for supported 2290c9563608SJanet Adkins * values 2291a0ec28b6SAdrian Ambrożewicz * @param mapComplete Callback to be called with retrieval result 2292a0ec28b6SAdrian Ambrożewicz */ 2293931edc79SEd Tanous template <typename Callback> 2294bd79bce8SPatrick Williams inline void retrieveUriToDbusMap( 2295bd79bce8SPatrick Williams const std::string& chassis, const std::string& node, Callback&& mapComplete) 2296a0ec28b6SAdrian Ambrożewicz { 229702da7c5aSEd Tanous decltype(sensors::paths)::const_iterator pathIt = 229802da7c5aSEd Tanous std::find_if(sensors::paths.cbegin(), sensors::paths.cend(), 229902da7c5aSEd Tanous [&node](auto&& val) { return val.first == node; }); 230002da7c5aSEd Tanous if (pathIt == sensors::paths.cend()) 2301a0ec28b6SAdrian Ambrożewicz { 230262598e31SEd Tanous BMCWEB_LOG_ERROR("Wrong node provided : {}", node); 23036804b5c8SEd Tanous std::map<std::string, std::string> noop; 23046804b5c8SEd Tanous mapComplete(boost::beast::http::status::bad_request, noop); 2305a0ec28b6SAdrian Ambrożewicz return; 2306a0ec28b6SAdrian Ambrożewicz } 2307d51e072fSKrzysztof Grobelny 230872374eb7SNan Zhou auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); 2309bd79bce8SPatrick Williams auto callback = 2310bd79bce8SPatrick Williams [asyncResp, mapCompleteCb = std::forward<Callback>(mapComplete)]( 2311a0ec28b6SAdrian Ambrożewicz const boost::beast::http::status status, 2312fe04d49cSNan Zhou const std::map<std::string, std::string>& uriToDbus) { 2313fe04d49cSNan Zhou mapCompleteCb(status, uriToDbus); 2314fe04d49cSNan Zhou }; 2315a0ec28b6SAdrian Ambrożewicz 2316a0ec28b6SAdrian Ambrożewicz auto resp = std::make_shared<SensorsAsyncResp>( 2317d51e072fSKrzysztof Grobelny asyncResp, chassis, pathIt->second, node, std::move(callback)); 2318a0ec28b6SAdrian Ambrożewicz getChassisData(resp); 2319a0ec28b6SAdrian Ambrożewicz } 2320a0ec28b6SAdrian Ambrożewicz 2321bacb2162SNan Zhou namespace sensors 2322bacb2162SNan Zhou { 2323928fefb9SNan Zhou 2324bacb2162SNan Zhou inline void getChassisCallback( 2325c1d019a6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2326c1d019a6SEd Tanous std::string_view chassisId, std::string_view chassisSubNode, 2327fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& sensorNames) 2328bacb2162SNan Zhou { 232962598e31SEd Tanous BMCWEB_LOG_DEBUG("getChassisCallback enter "); 2330bacb2162SNan Zhou 2331c1d019a6SEd Tanous nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"]; 2332c1d019a6SEd Tanous for (const std::string& sensor : *sensorNames) 2333bacb2162SNan Zhou { 233462598e31SEd Tanous BMCWEB_LOG_DEBUG("Adding sensor: {}", sensor); 2335bacb2162SNan Zhou 2336bacb2162SNan Zhou sdbusplus::message::object_path path(sensor); 2337bacb2162SNan Zhou std::string sensorName = path.filename(); 2338bacb2162SNan Zhou if (sensorName.empty()) 2339bacb2162SNan Zhou { 234062598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid sensor path: {}", sensor); 2341c1d019a6SEd Tanous messages::internalError(asyncResp->res); 2342bacb2162SNan Zhou return; 2343bacb2162SNan Zhou } 2344c1d019a6SEd Tanous std::string type = path.parent_path().filename(); 23451516c21bSJanet Adkins std::string id = redfish::sensor_utils::getSensorId(sensorName, type); 2346c1d019a6SEd Tanous 23471476687dSEd Tanous nlohmann::json::object_t member; 2348ef4c65b7SEd Tanous member["@odata.id"] = boost::urls::format( 2349ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/{}/{}", chassisId, chassisSubNode, id); 2350c1d019a6SEd Tanous 2351b2ba3072SPatrick Williams entriesArray.emplace_back(std::move(member)); 2352bacb2162SNan Zhou } 2353bacb2162SNan Zhou 2354c1d019a6SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 235562598e31SEd Tanous BMCWEB_LOG_DEBUG("getChassisCallback exit"); 2356bacb2162SNan Zhou } 2357e6bd846dSNan Zhou 2358ac106bf6SEd Tanous inline void handleSensorCollectionGet( 2359ac106bf6SEd Tanous App& app, const crow::Request& req, 2360ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2361de167a6fSNan Zhou const std::string& chassisId) 2362de167a6fSNan Zhou { 2363de167a6fSNan Zhou query_param::QueryCapabilities capabilities = { 2364de167a6fSNan Zhou .canDelegateExpandLevel = 1, 2365de167a6fSNan Zhou }; 2366de167a6fSNan Zhou query_param::Query delegatedQuery; 2367ac106bf6SEd Tanous if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp, 2368de167a6fSNan Zhou delegatedQuery, capabilities)) 2369de167a6fSNan Zhou { 2370de167a6fSNan Zhou return; 2371de167a6fSNan Zhou } 2372de167a6fSNan Zhou 2373de167a6fSNan Zhou if (delegatedQuery.expandType != query_param::ExpandType::None) 2374de167a6fSNan Zhou { 2375de167a6fSNan Zhou // we perform efficient expand. 2376ac106bf6SEd Tanous auto sensorsAsyncResp = std::make_shared<SensorsAsyncResp>( 2377ac106bf6SEd Tanous asyncResp, chassisId, sensors::dbus::sensorPaths, 23780c728b42SJanet Adkins sensors::sensorsNodeStr, 2379de167a6fSNan Zhou /*efficientExpand=*/true); 2380ac106bf6SEd Tanous getChassisData(sensorsAsyncResp); 2381de167a6fSNan Zhou 238262598e31SEd Tanous BMCWEB_LOG_DEBUG( 238362598e31SEd Tanous "SensorCollection doGet exit via efficient expand handler"); 2384de167a6fSNan Zhou return; 23850bad320cSEd Tanous } 2386de167a6fSNan Zhou 2387de167a6fSNan Zhou // We get all sensors as hyperlinkes in the chassis (this 2388de167a6fSNan Zhou // implies we reply on the default query parameters handler) 23890c728b42SJanet Adkins getChassis(asyncResp, chassisId, sensors::sensorsNodeStr, dbus::sensorPaths, 2390ac106bf6SEd Tanous std::bind_front(sensors::getChassisCallback, asyncResp, 23910c728b42SJanet Adkins chassisId, sensors::sensorsNodeStr)); 2392c1d019a6SEd Tanous } 23937f1cc26dSEd Tanous 2394c1d019a6SEd Tanous inline void 2395c1d019a6SEd Tanous getSensorFromDbus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2396c1d019a6SEd Tanous const std::string& sensorPath, 2397c1d019a6SEd Tanous const ::dbus::utility::MapperGetObject& mapperResponse) 2398c1d019a6SEd Tanous { 2399c1d019a6SEd Tanous if (mapperResponse.size() != 1) 2400c1d019a6SEd Tanous { 2401c1d019a6SEd Tanous messages::internalError(asyncResp->res); 2402c1d019a6SEd Tanous return; 2403c1d019a6SEd Tanous } 2404c1d019a6SEd Tanous const auto& valueIface = *mapperResponse.begin(); 2405c1d019a6SEd Tanous const std::string& connectionName = valueIface.first; 240662598e31SEd Tanous BMCWEB_LOG_DEBUG("Looking up {}", connectionName); 240762598e31SEd Tanous BMCWEB_LOG_DEBUG("Path {}", sensorPath); 2408c1343bf6SKrzysztof Grobelny 2409*deae6a78SEd Tanous ::dbus::utility::getAllProperties( 2410c1343bf6SKrzysztof Grobelny *crow::connections::systemBus, connectionName, sensorPath, "", 2411c1d019a6SEd Tanous [asyncResp, 24125e7e2dc5SEd Tanous sensorPath](const boost::system::error_code& ec, 2413c1d019a6SEd Tanous const ::dbus::utility::DBusPropertiesMap& valuesDict) { 2414c1d019a6SEd Tanous if (ec) 2415c1d019a6SEd Tanous { 2416c1d019a6SEd Tanous messages::internalError(asyncResp->res); 2417c1d019a6SEd Tanous return; 2418c1d019a6SEd Tanous } 2419c1d019a6SEd Tanous sdbusplus::message::object_path path(sensorPath); 2420c1d019a6SEd Tanous std::string name = path.filename(); 2421c1d019a6SEd Tanous path = path.parent_path(); 2422c1d019a6SEd Tanous std::string type = path.filename(); 2423c9563608SJanet Adkins sensor_utils::objectPropertiesToJson( 24240c728b42SJanet Adkins name, type, sensor_utils::ChassisSubNode::sensorsNode, 24250c728b42SJanet Adkins valuesDict, asyncResp->res.jsonValue, nullptr); 2426c1343bf6SKrzysztof Grobelny }); 2427de167a6fSNan Zhou } 2428de167a6fSNan Zhou 2429e6bd846dSNan Zhou inline void handleSensorGet(App& app, const crow::Request& req, 2430c1d019a6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2431677bb756SEd Tanous const std::string& chassisId, 2432c1d019a6SEd Tanous const std::string& sensorId) 2433e6bd846dSNan Zhou { 2434c1d019a6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2435e6bd846dSNan Zhou { 2436e6bd846dSNan Zhou return; 2437e6bd846dSNan Zhou } 2438c71d6125SEd Tanous std::pair<std::string, std::string> nameType = 24391516c21bSJanet Adkins redfish::sensor_utils::splitSensorNameAndType(sensorId); 2440c71d6125SEd Tanous if (nameType.first.empty() || nameType.second.empty()) 2441c1d019a6SEd Tanous { 2442c1d019a6SEd Tanous messages::resourceNotFound(asyncResp->res, sensorId, "Sensor"); 2443c1d019a6SEd Tanous return; 2444c1d019a6SEd Tanous } 2445c71d6125SEd Tanous 2446ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 2447ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/Sensors/{}", chassisId, sensorId); 2448c1d019a6SEd Tanous 244962598e31SEd Tanous BMCWEB_LOG_DEBUG("Sensor doGet enter"); 2450e6bd846dSNan Zhou 24512b73119cSGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 2452e6bd846dSNan Zhou "xyz.openbmc_project.Sensor.Value"}; 2453c71d6125SEd Tanous std::string sensorPath = "/xyz/openbmc_project/sensors/" + nameType.first + 2454c71d6125SEd Tanous '/' + nameType.second; 2455e6bd846dSNan Zhou // Get a list of all of the sensors that implement Sensor.Value 2456e6bd846dSNan Zhou // and get the path and service name associated with the sensor 24572b73119cSGeorge Liu ::dbus::utility::getDbusObject( 24582b73119cSGeorge Liu sensorPath, interfaces, 2459aec0ec30SMyung Bae [asyncResp, sensorId, 24602b73119cSGeorge Liu sensorPath](const boost::system::error_code& ec, 2461c1d019a6SEd Tanous const ::dbus::utility::MapperGetObject& subtree) { 246262598e31SEd Tanous BMCWEB_LOG_DEBUG("respHandler1 enter"); 2463aec0ec30SMyung Bae if (ec == boost::system::errc::io_error) 2464aec0ec30SMyung Bae { 246562598e31SEd Tanous BMCWEB_LOG_WARNING("Sensor not found from getSensorPaths"); 2466aec0ec30SMyung Bae messages::resourceNotFound(asyncResp->res, sensorId, "Sensor"); 2467aec0ec30SMyung Bae return; 2468aec0ec30SMyung Bae } 2469e6bd846dSNan Zhou if (ec) 2470e6bd846dSNan Zhou { 2471c1d019a6SEd Tanous messages::internalError(asyncResp->res); 247262598e31SEd Tanous BMCWEB_LOG_ERROR( 247362598e31SEd Tanous "Sensor getSensorPaths resp_handler: Dbus error {}", ec); 2474e6bd846dSNan Zhou return; 2475e6bd846dSNan Zhou } 2476c1d019a6SEd Tanous getSensorFromDbus(asyncResp, sensorPath, subtree); 247762598e31SEd Tanous BMCWEB_LOG_DEBUG("respHandler1 exit"); 24782b73119cSGeorge Liu }); 2479e6bd846dSNan Zhou } 2480e6bd846dSNan Zhou 2481bacb2162SNan Zhou } // namespace sensors 2482bacb2162SNan Zhou 24837e860f15SJohn Edward Broadbent inline void requestRoutesSensorCollection(App& app) 248495a3ecadSAnthony Wilson { 24857e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/") 2486ed398213SEd Tanous .privileges(redfish::privileges::getSensorCollection) 2487002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2488de167a6fSNan Zhou std::bind_front(sensors::handleSensorCollectionGet, std::ref(app))); 248995a3ecadSAnthony Wilson } 249095a3ecadSAnthony Wilson 24917e860f15SJohn Edward Broadbent inline void requestRoutesSensor(App& app) 249295a3ecadSAnthony Wilson { 24937e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/") 2494ed398213SEd Tanous .privileges(redfish::privileges::getSensor) 2495002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2496e6bd846dSNan Zhou std::bind_front(sensors::handleSensorGet, std::ref(app))); 249795a3ecadSAnthony Wilson } 249895a3ecadSAnthony Wilson 249908777fb0SLewanczyk, Dawid } // namespace redfish 2500