xref: /openbmc/bmcweb/features/redfish/lib/sensors.hpp (revision 504af5a0568171b72caf13234cc81380b261fa21)
140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
340e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
408777fb0SLewanczyk, Dawid #pragma once
508777fb0SLewanczyk, Dawid 
6d7857201SEd Tanous #include "bmcweb_config.h"
7d7857201SEd Tanous 
83ccb3adbSEd Tanous #include "app.hpp"
9d7857201SEd Tanous #include "async_resp.hpp"
103ccb3adbSEd Tanous #include "dbus_singleton.hpp"
117a1dbc48SGeorge Liu #include "dbus_utility.hpp"
12d7857201SEd Tanous #include "error_messages.hpp"
13539d8c6bSEd Tanous #include "generated/enums/redundancy.hpp"
14aaf08ac7SMatt Simmering #include "generated/enums/resource.hpp"
15d7857201SEd Tanous #include "http_request.hpp"
16d7857201SEd Tanous #include "logging.hpp"
173ccb3adbSEd Tanous #include "query.hpp"
183ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
1950ebd4afSEd Tanous #include "str_utility.hpp"
203ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
213ccb3adbSEd Tanous #include "utils/json_utils.hpp"
223ccb3adbSEd Tanous #include "utils/query_param.hpp"
231516c21bSJanet Adkins #include "utils/sensor_utils.hpp"
240ec8b83dSEd Tanous 
25d7857201SEd Tanous #include <asm-generic/errno.h>
26d7857201SEd Tanous 
27d7857201SEd Tanous #include <boost/beast/http/status.hpp>
28d7857201SEd Tanous #include <boost/beast/http/verb.hpp>
29e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
30ef4c65b7SEd Tanous #include <boost/url/format.hpp>
31d7857201SEd Tanous #include <boost/url/url.hpp>
32d7857201SEd Tanous #include <nlohmann/json.hpp>
33d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp>
3486d89ed7SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
351214b7e7SGunnar Mills 
36d7857201SEd Tanous #include <algorithm>
377a1dbc48SGeorge Liu #include <array>
381214b7e7SGunnar Mills #include <cmath>
39d7857201SEd Tanous #include <cstddef>
40d7857201SEd Tanous #include <cstdint>
41d7857201SEd Tanous #include <functional>
42fe04d49cSNan Zhou #include <iterator>
43fe04d49cSNan Zhou #include <map>
44d7857201SEd Tanous #include <memory>
45d7857201SEd Tanous #include <optional>
463544d2a7SEd Tanous #include <ranges>
47fe04d49cSNan Zhou #include <set>
48d7857201SEd Tanous #include <span>
4918f8f608SEd Tanous #include <string>
507a1dbc48SGeorge Liu #include <string_view>
51d7857201SEd Tanous #include <unordered_map>
52b5a76932SEd Tanous #include <utility>
53abf2add6SEd Tanous #include <variant>
54d7857201SEd Tanous #include <vector>
5508777fb0SLewanczyk, Dawid 
561abe55efSEd Tanous namespace redfish
571abe55efSEd Tanous {
5808777fb0SLewanczyk, Dawid 
59a0ec28b6SAdrian Ambrożewicz namespace sensors
60a0ec28b6SAdrian Ambrożewicz {
61a0ec28b6SAdrian Ambrożewicz 
6202da7c5aSEd Tanous // clang-format off
63a0ec28b6SAdrian Ambrożewicz namespace dbus
64a0ec28b6SAdrian Ambrożewicz {
65cf9e417dSEd Tanous constexpr auto powerPaths = std::to_array<std::string_view>({
6602da7c5aSEd Tanous     "/xyz/openbmc_project/sensors/voltage",
6702da7c5aSEd Tanous     "/xyz/openbmc_project/sensors/power"
6802da7c5aSEd Tanous });
69c2bf7f99SWludzik, Jozef 
7025b54dbaSEd Tanous constexpr auto getSensorPaths(){
7125b54dbaSEd Tanous     if constexpr(BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM){
7225b54dbaSEd Tanous     return std::to_array<std::string_view>({
7302da7c5aSEd Tanous         "/xyz/openbmc_project/sensors/power",
74a0ec28b6SAdrian Ambrożewicz         "/xyz/openbmc_project/sensors/current",
757088690cSBasheer Ahmed Muddebihal         "/xyz/openbmc_project/sensors/airflow",
765deabed9SGunnar Mills         "/xyz/openbmc_project/sensors/humidity",
77e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/voltage",
78e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/fan_tach",
79e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/temperature",
80e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/fan_pwm",
81e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/altitude",
82e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/energy",
8325b54dbaSEd Tanous         "/xyz/openbmc_project/sensors/utilization"});
8425b54dbaSEd Tanous     } else {
8525b54dbaSEd Tanous       return  std::to_array<std::string_view>({"/xyz/openbmc_project/sensors/power",
8625b54dbaSEd Tanous         "/xyz/openbmc_project/sensors/current",
8725b54dbaSEd Tanous         "/xyz/openbmc_project/sensors/airflow",
8825b54dbaSEd Tanous         "/xyz/openbmc_project/sensors/humidity",
8925b54dbaSEd Tanous         "/xyz/openbmc_project/sensors/utilization"});
9025b54dbaSEd Tanous }
9125b54dbaSEd Tanous }
9225b54dbaSEd Tanous 
9325b54dbaSEd Tanous constexpr auto sensorPaths = getSensorPaths();
9402da7c5aSEd Tanous 
95cf9e417dSEd Tanous constexpr auto thermalPaths = std::to_array<std::string_view>({
9602da7c5aSEd Tanous     "/xyz/openbmc_project/sensors/fan_tach",
97a0ec28b6SAdrian Ambrożewicz     "/xyz/openbmc_project/sensors/temperature",
9802da7c5aSEd Tanous     "/xyz/openbmc_project/sensors/fan_pwm"
9902da7c5aSEd Tanous });
10002da7c5aSEd Tanous 
101c2bf7f99SWludzik, Jozef } // namespace dbus
10202da7c5aSEd Tanous // clang-format on
10302da7c5aSEd Tanous 
1040c728b42SJanet Adkins constexpr std::string_view powerNodeStr = sensor_utils::chassisSubNodeToString(
1050c728b42SJanet Adkins     sensor_utils::ChassisSubNode::powerNode);
1060c728b42SJanet Adkins constexpr std::string_view sensorsNodeStr =
1070c728b42SJanet Adkins     sensor_utils::chassisSubNodeToString(
1080c728b42SJanet Adkins         sensor_utils::ChassisSubNode::sensorsNode);
1090c728b42SJanet Adkins constexpr std::string_view thermalNodeStr =
1100c728b42SJanet Adkins     sensor_utils::chassisSubNodeToString(
1110c728b42SJanet Adkins         sensor_utils::ChassisSubNode::thermalNode);
1120c728b42SJanet Adkins 
113cf9e417dSEd Tanous using sensorPair =
114cf9e417dSEd Tanous     std::pair<std::string_view, std::span<const std::string_view>>;
11502da7c5aSEd Tanous static constexpr std::array<sensorPair, 3> paths = {
1160c728b42SJanet Adkins     {{sensors::powerNodeStr, dbus::powerPaths},
1170c728b42SJanet Adkins      {sensors::sensorsNodeStr, dbus::sensorPaths},
1180c728b42SJanet Adkins      {sensors::thermalNodeStr, dbus::thermalPaths}}};
119c2bf7f99SWludzik, Jozef 
120a0ec28b6SAdrian Ambrożewicz } // namespace sensors
121a0ec28b6SAdrian Ambrożewicz 
12208777fb0SLewanczyk, Dawid /**
123588c3f0dSKowalski, Kamil  * SensorsAsyncResp
12408777fb0SLewanczyk, Dawid  * Gathers data needed for response processing after async calls are done
12508777fb0SLewanczyk, Dawid  */
1261abe55efSEd Tanous class SensorsAsyncResp
1271abe55efSEd Tanous {
12808777fb0SLewanczyk, Dawid   public:
129a0ec28b6SAdrian Ambrożewicz     using DataCompleteCb = std::function<void(
130a0ec28b6SAdrian Ambrożewicz         const boost::beast::http::status status,
131fe04d49cSNan Zhou         const std::map<std::string, std::string>& uriToDbus)>;
132a0ec28b6SAdrian Ambrożewicz 
133a0ec28b6SAdrian Ambrożewicz     struct SensorData
134a0ec28b6SAdrian Ambrożewicz     {
135f836c1d8SEd Tanous         std::string name;
136a0ec28b6SAdrian Ambrożewicz         std::string uri;
137f836c1d8SEd Tanous         std::string dbusPath;
138a0ec28b6SAdrian Ambrożewicz     };
139a0ec28b6SAdrian Ambrożewicz 
1408a592810SEd Tanous     SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
1418d1b46d7Szhanghch05                      const std::string& chassisIdIn,
142cf9e417dSEd Tanous                      std::span<const std::string_view> typesIn,
14302da7c5aSEd Tanous                      std::string_view subNode) :
144bd79bce8SPatrick Williams         asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
145bd79bce8SPatrick Williams         chassisSubNode(subNode), efficientExpand(false)
1461214b7e7SGunnar Mills     {}
14708777fb0SLewanczyk, Dawid 
148a0ec28b6SAdrian Ambrożewicz     // Store extra data about sensor mapping and return it in callback
1498a592810SEd Tanous     SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
1508d1b46d7Szhanghch05                      const std::string& chassisIdIn,
151cf9e417dSEd Tanous                      std::span<const std::string_view> typesIn,
15202da7c5aSEd Tanous                      std::string_view subNode,
153a0ec28b6SAdrian Ambrożewicz                      DataCompleteCb&& creationComplete) :
154bd79bce8SPatrick Williams         asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
155bd79bce8SPatrick Williams         chassisSubNode(subNode), efficientExpand(false),
156bd79bce8SPatrick Williams         metadata{std::vector<SensorData>()},
157a0ec28b6SAdrian Ambrożewicz         dataComplete{std::move(creationComplete)}
158a0ec28b6SAdrian Ambrożewicz     {}
159a0ec28b6SAdrian Ambrożewicz 
160928fefb9SNan Zhou     // sensor collections expand
1618a592810SEd Tanous     SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
162928fefb9SNan Zhou                      const std::string& chassisIdIn,
163cf9e417dSEd Tanous                      std::span<const std::string_view> typesIn,
1648a592810SEd Tanous                      const std::string_view& subNode, bool efficientExpandIn) :
165bd79bce8SPatrick Williams         asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
166bd79bce8SPatrick Williams         chassisSubNode(subNode), efficientExpand(efficientExpandIn)
167928fefb9SNan Zhou     {}
168928fefb9SNan Zhou 
1691abe55efSEd Tanous     ~SensorsAsyncResp()
1701abe55efSEd Tanous     {
1718d1b46d7Szhanghch05         if (asyncResp->res.result() ==
1728d1b46d7Szhanghch05             boost::beast::http::status::internal_server_error)
1731abe55efSEd Tanous         {
1741abe55efSEd Tanous             // Reset the json object to clear out any data that made it in
1751abe55efSEd Tanous             // before the error happened todo(ed) handle error condition with
1761abe55efSEd Tanous             // proper code
1778d1b46d7Szhanghch05             asyncResp->res.jsonValue = nlohmann::json::object();
17808777fb0SLewanczyk, Dawid         }
179a0ec28b6SAdrian Ambrożewicz 
180a0ec28b6SAdrian Ambrożewicz         if (dataComplete && metadata)
181a0ec28b6SAdrian Ambrożewicz         {
182fe04d49cSNan Zhou             std::map<std::string, std::string> map;
1838d1b46d7Szhanghch05             if (asyncResp->res.result() == boost::beast::http::status::ok)
184a0ec28b6SAdrian Ambrożewicz             {
185a0ec28b6SAdrian Ambrożewicz                 for (auto& sensor : *metadata)
186a0ec28b6SAdrian Ambrożewicz                 {
187c1d019a6SEd Tanous                     map.emplace(sensor.uri, sensor.dbusPath);
188a0ec28b6SAdrian Ambrożewicz                 }
189a0ec28b6SAdrian Ambrożewicz             }
1908d1b46d7Szhanghch05             dataComplete(asyncResp->res.result(), map);
191a0ec28b6SAdrian Ambrożewicz         }
19208777fb0SLewanczyk, Dawid     }
193588c3f0dSKowalski, Kamil 
194ecd6a3a2SEd Tanous     SensorsAsyncResp(const SensorsAsyncResp&) = delete;
195ecd6a3a2SEd Tanous     SensorsAsyncResp(SensorsAsyncResp&&) = delete;
196ecd6a3a2SEd Tanous     SensorsAsyncResp& operator=(const SensorsAsyncResp&) = delete;
197ecd6a3a2SEd Tanous     SensorsAsyncResp& operator=(SensorsAsyncResp&&) = delete;
198ecd6a3a2SEd Tanous 
199a0ec28b6SAdrian Ambrożewicz     void addMetadata(const nlohmann::json& sensorObject,
200c1d019a6SEd Tanous                      const std::string& dbusPath)
201a0ec28b6SAdrian Ambrożewicz     {
202a0ec28b6SAdrian Ambrożewicz         if (metadata)
203a0ec28b6SAdrian Ambrożewicz         {
204c1d019a6SEd Tanous             metadata->emplace_back(SensorData{
205c1d019a6SEd Tanous                 sensorObject["Name"], sensorObject["@odata.id"], dbusPath});
206a0ec28b6SAdrian Ambrożewicz         }
207a0ec28b6SAdrian Ambrożewicz     }
208a0ec28b6SAdrian Ambrożewicz 
209a0ec28b6SAdrian Ambrożewicz     void updateUri(const std::string& name, const std::string& uri)
210a0ec28b6SAdrian Ambrożewicz     {
211a0ec28b6SAdrian Ambrożewicz         if (metadata)
212a0ec28b6SAdrian Ambrożewicz         {
213a0ec28b6SAdrian Ambrożewicz             for (auto& sensor : *metadata)
214a0ec28b6SAdrian Ambrożewicz             {
215a0ec28b6SAdrian Ambrożewicz                 if (sensor.name == name)
216a0ec28b6SAdrian Ambrożewicz                 {
217a0ec28b6SAdrian Ambrożewicz                     sensor.uri = uri;
218a0ec28b6SAdrian Ambrożewicz                 }
219a0ec28b6SAdrian Ambrożewicz             }
220a0ec28b6SAdrian Ambrożewicz         }
221a0ec28b6SAdrian Ambrożewicz     }
222a0ec28b6SAdrian Ambrożewicz 
2238d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
224a0ec28b6SAdrian Ambrożewicz     const std::string chassisId;
225cf9e417dSEd Tanous     const std::span<const std::string_view> types;
226a0ec28b6SAdrian Ambrożewicz     const std::string chassisSubNode;
227928fefb9SNan Zhou     const bool efficientExpand;
228a0ec28b6SAdrian Ambrożewicz 
229a0ec28b6SAdrian Ambrożewicz   private:
230a0ec28b6SAdrian Ambrożewicz     std::optional<std::vector<SensorData>> metadata;
231a0ec28b6SAdrian Ambrożewicz     DataCompleteCb dataComplete;
23208777fb0SLewanczyk, Dawid };
23308777fb0SLewanczyk, Dawid 
234c9563608SJanet Adkins using InventoryItem = sensor_utils::InventoryItem;
235adc4f0dbSShawn McCarney 
236adc4f0dbSShawn McCarney /**
237413961deSRichard Marian Thomaiyar  * @brief Get objects with connection necessary for sensors
238588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp Pointer to object holding response data
23908777fb0SLewanczyk, Dawid  * @param sensorNames Sensors retrieved from chassis
24008777fb0SLewanczyk, Dawid  * @param callback Callback for processing gathered connections
24108777fb0SLewanczyk, Dawid  */
24208777fb0SLewanczyk, Dawid template <typename Callback>
243413961deSRichard Marian Thomaiyar void getObjectsWithConnection(
24481ce609eSEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
245fe04d49cSNan Zhou     const std::shared_ptr<std::set<std::string>>& sensorNames,
2461abe55efSEd Tanous     Callback&& callback)
2471abe55efSEd Tanous {
24862598e31SEd Tanous     BMCWEB_LOG_DEBUG("getObjectsWithConnection enter");
24903b5bae3SJames Feist     const std::string path = "/xyz/openbmc_project/sensors";
250e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
25108777fb0SLewanczyk, Dawid         "xyz.openbmc_project.Sensor.Value"};
25208777fb0SLewanczyk, Dawid 
253e99073f5SGeorge Liu     // Make call to ObjectMapper to find all sensors objects
254e99073f5SGeorge Liu     dbus::utility::getSubTree(
255e99073f5SGeorge Liu         path, 2, interfaces,
2568cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), sensorsAsyncResp,
257e99073f5SGeorge Liu          sensorNames](const boost::system::error_code& ec,
258002d39b4SEd Tanous                       const dbus::utility::MapperGetSubTreeResponse& subtree) {
259e99073f5SGeorge Liu             // Response handler for parsing objects subtree
26062598e31SEd Tanous             BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler enter");
2611abe55efSEd Tanous             if (ec)
2621abe55efSEd Tanous             {
2638d1b46d7Szhanghch05                 messages::internalError(sensorsAsyncResp->asyncResp->res);
26462598e31SEd Tanous                 BMCWEB_LOG_ERROR(
26562598e31SEd Tanous                     "getObjectsWithConnection resp_handler: Dbus error {}", ec);
26608777fb0SLewanczyk, Dawid                 return;
26708777fb0SLewanczyk, Dawid             }
26808777fb0SLewanczyk, Dawid 
26962598e31SEd Tanous             BMCWEB_LOG_DEBUG("Found {} subtrees", subtree.size());
27008777fb0SLewanczyk, Dawid 
271bd79bce8SPatrick Williams             // Make unique list of connections only for requested sensor types
272bd79bce8SPatrick Williams             // and found in the chassis
273fe04d49cSNan Zhou             std::set<std::string> connections;
274413961deSRichard Marian Thomaiyar             std::set<std::pair<std::string, std::string>> objectsWithConnection;
27508777fb0SLewanczyk, Dawid 
27662598e31SEd Tanous             BMCWEB_LOG_DEBUG("sensorNames list count: {}", sensorNames->size());
27749c53ac9SJohnathan Mantey             for (const std::string& tsensor : *sensorNames)
2781abe55efSEd Tanous             {
27962598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Sensor to find: {}", tsensor);
28008777fb0SLewanczyk, Dawid             }
28108777fb0SLewanczyk, Dawid 
282bd79bce8SPatrick Williams             for (const std::pair<std::string,
283bd79bce8SPatrick Williams                                  std::vector<std::pair<
284bd79bce8SPatrick Williams                                      std::string, std::vector<std::string>>>>&
2851abe55efSEd Tanous                      object : subtree)
2861abe55efSEd Tanous             {
28749c53ac9SJohnathan Mantey                 if (sensorNames->find(object.first) != sensorNames->end())
2881abe55efSEd Tanous                 {
28949c53ac9SJohnathan Mantey                     for (const std::pair<std::string, std::vector<std::string>>&
2901abe55efSEd Tanous                              objData : object.second)
2911abe55efSEd Tanous                     {
292bd79bce8SPatrick Williams                         BMCWEB_LOG_DEBUG("Adding connection: {}",
293bd79bce8SPatrick Williams                                          objData.first);
29408777fb0SLewanczyk, Dawid                         connections.insert(objData.first);
295de629b6eSShawn McCarney                         objectsWithConnection.insert(
296de629b6eSShawn McCarney                             std::make_pair(object.first, objData.first));
29708777fb0SLewanczyk, Dawid                     }
29808777fb0SLewanczyk, Dawid                 }
29908777fb0SLewanczyk, Dawid             }
30062598e31SEd Tanous             BMCWEB_LOG_DEBUG("Found {} connections", connections.size());
301413961deSRichard Marian Thomaiyar             callback(std::move(connections), std::move(objectsWithConnection));
30262598e31SEd Tanous             BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler exit");
303e99073f5SGeorge Liu         });
30462598e31SEd Tanous     BMCWEB_LOG_DEBUG("getObjectsWithConnection exit");
305413961deSRichard Marian Thomaiyar }
306413961deSRichard Marian Thomaiyar 
307413961deSRichard Marian Thomaiyar /**
308413961deSRichard Marian Thomaiyar  * @brief Create connections necessary for sensors
309413961deSRichard Marian Thomaiyar  * @param SensorsAsyncResp Pointer to object holding response data
310413961deSRichard Marian Thomaiyar  * @param sensorNames Sensors retrieved from chassis
311413961deSRichard Marian Thomaiyar  * @param callback Callback for processing gathered connections
312413961deSRichard Marian Thomaiyar  */
313413961deSRichard Marian Thomaiyar template <typename Callback>
314daadfb2eSEd Tanous void getConnections(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
315daadfb2eSEd Tanous                     const std::shared_ptr<std::set<std::string>>& sensorNames,
316413961deSRichard Marian Thomaiyar                     Callback&& callback)
317413961deSRichard Marian Thomaiyar {
318413961deSRichard Marian Thomaiyar     auto objectsWithConnectionCb =
3198cb2c024SEd Tanous         [callback = std::forward<Callback>(callback)](
3208cb2c024SEd Tanous             const std::set<std::string>& connections,
321413961deSRichard Marian Thomaiyar             const std::set<std::pair<std::string, std::string>>&
3223174e4dfSEd Tanous             /*objectsWithConnection*/) { callback(connections); };
32381ce609eSEd Tanous     getObjectsWithConnection(sensorsAsyncResp, sensorNames,
324413961deSRichard Marian Thomaiyar                              std::move(objectsWithConnectionCb));
32508777fb0SLewanczyk, Dawid }
32608777fb0SLewanczyk, Dawid 
32708777fb0SLewanczyk, Dawid /**
32849c53ac9SJohnathan Mantey  * @brief Shrinks the list of sensors for processing
32949c53ac9SJohnathan Mantey  * @param SensorsAysncResp  The class holding the Redfish response
33049c53ac9SJohnathan Mantey  * @param allSensors  A list of all the sensors associated to the
33149c53ac9SJohnathan Mantey  * chassis element (i.e. baseboard, front panel, etc...)
33249c53ac9SJohnathan Mantey  * @param activeSensors A list that is a reduction of the incoming
33349c53ac9SJohnathan Mantey  * allSensors list.  Eliminate Thermal sensors when a Power request is
33449c53ac9SJohnathan Mantey  * made, and eliminate Power sensors when a Thermal request is made.
33549c53ac9SJohnathan Mantey  */
33623a21a1cSEd Tanous inline void reduceSensorList(
3377f1cc26dSEd Tanous     crow::Response& res, std::string_view chassisSubNode,
338cf9e417dSEd Tanous     std::span<const std::string_view> sensorTypes,
33949c53ac9SJohnathan Mantey     const std::vector<std::string>* allSensors,
340fe04d49cSNan Zhou     const std::shared_ptr<std::set<std::string>>& activeSensors)
34149c53ac9SJohnathan Mantey {
34249c53ac9SJohnathan Mantey     if ((allSensors == nullptr) || (activeSensors == nullptr))
34349c53ac9SJohnathan Mantey     {
3447f1cc26dSEd Tanous         messages::resourceNotFound(res, chassisSubNode,
3450c728b42SJanet Adkins                                    chassisSubNode == sensors::thermalNodeStr
346a0ec28b6SAdrian Ambrożewicz                                        ? "Temperatures"
34749c53ac9SJohnathan Mantey                                        : "Voltages");
34849c53ac9SJohnathan Mantey 
34949c53ac9SJohnathan Mantey         return;
35049c53ac9SJohnathan Mantey     }
35149c53ac9SJohnathan Mantey     if (allSensors->empty())
35249c53ac9SJohnathan Mantey     {
35349c53ac9SJohnathan Mantey         // Nothing to do, the activeSensors object is also empty
35449c53ac9SJohnathan Mantey         return;
35549c53ac9SJohnathan Mantey     }
35649c53ac9SJohnathan Mantey 
3577f1cc26dSEd Tanous     for (std::string_view type : sensorTypes)
35849c53ac9SJohnathan Mantey     {
35949c53ac9SJohnathan Mantey         for (const std::string& sensor : *allSensors)
36049c53ac9SJohnathan Mantey         {
36111ba3979SEd Tanous             if (sensor.starts_with(type))
36249c53ac9SJohnathan Mantey             {
36349c53ac9SJohnathan Mantey                 activeSensors->emplace(sensor);
36449c53ac9SJohnathan Mantey             }
36549c53ac9SJohnathan Mantey         }
36649c53ac9SJohnathan Mantey     }
36749c53ac9SJohnathan Mantey }
36849c53ac9SJohnathan Mantey 
3697f1cc26dSEd Tanous /*
3707f1cc26dSEd Tanous  *Populates the top level collection for a given subnode.  Populates
3717f1cc26dSEd Tanous  *SensorCollection, Power, or Thermal schemas.
3727f1cc26dSEd Tanous  *
3737f1cc26dSEd Tanous  * */
3747f1cc26dSEd Tanous inline void populateChassisNode(nlohmann::json& jsonValue,
3757f1cc26dSEd Tanous                                 std::string_view chassisSubNode)
3767f1cc26dSEd Tanous {
3770c728b42SJanet Adkins     if (chassisSubNode == sensors::powerNodeStr)
3787f1cc26dSEd Tanous     {
3797f1cc26dSEd Tanous         jsonValue["@odata.type"] = "#Power.v1_5_2.Power";
3807f1cc26dSEd Tanous     }
3810c728b42SJanet Adkins     else if (chassisSubNode == sensors::thermalNodeStr)
3827f1cc26dSEd Tanous     {
3837f1cc26dSEd Tanous         jsonValue["@odata.type"] = "#Thermal.v1_4_0.Thermal";
3847f1cc26dSEd Tanous         jsonValue["Fans"] = nlohmann::json::array();
3857f1cc26dSEd Tanous         jsonValue["Temperatures"] = nlohmann::json::array();
3867f1cc26dSEd Tanous     }
3870c728b42SJanet Adkins     else if (chassisSubNode == sensors::sensorsNodeStr)
3887f1cc26dSEd Tanous     {
3897f1cc26dSEd Tanous         jsonValue["@odata.type"] = "#SensorCollection.SensorCollection";
3907f1cc26dSEd Tanous         jsonValue["Description"] = "Collection of Sensors for this Chassis";
3917f1cc26dSEd Tanous         jsonValue["Members"] = nlohmann::json::array();
3927f1cc26dSEd Tanous         jsonValue["Members@odata.count"] = 0;
3937f1cc26dSEd Tanous     }
3947f1cc26dSEd Tanous 
3950c728b42SJanet Adkins     if (chassisSubNode != sensors::sensorsNodeStr)
3967f1cc26dSEd Tanous     {
3977f1cc26dSEd Tanous         jsonValue["Id"] = chassisSubNode;
3987f1cc26dSEd Tanous     }
3997f1cc26dSEd Tanous     jsonValue["Name"] = chassisSubNode;
4007f1cc26dSEd Tanous }
4017f1cc26dSEd Tanous 
40249c53ac9SJohnathan Mantey /**
40308777fb0SLewanczyk, Dawid  * @brief Retrieves requested chassis sensors and redundancy data from DBus .
404588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
40508777fb0SLewanczyk, Dawid  * @param callback  Callback for next step in gathered sensor processing
40608777fb0SLewanczyk, Dawid  */
40708777fb0SLewanczyk, Dawid template <typename Callback>
4087f1cc26dSEd Tanous void getChassis(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4097f1cc26dSEd Tanous                 std::string_view chassisId, std::string_view chassisSubNode,
410cf9e417dSEd Tanous                 std::span<const std::string_view> sensorTypes,
411cf9e417dSEd Tanous                 Callback&& callback)
4121abe55efSEd Tanous {
41362598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassis enter");
4147a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
41549c53ac9SJohnathan Mantey         "xyz.openbmc_project.Inventory.Item.Board",
416adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Item.Chassis"};
4177a1dbc48SGeorge Liu 
4187a1dbc48SGeorge Liu     // Get the Chassis Collection
4197a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
4207a1dbc48SGeorge Liu         "/xyz/openbmc_project/inventory", 0, interfaces,
4218cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), asyncResp,
4227f1cc26dSEd Tanous          chassisIdStr{std::string(chassisId)},
4234e0d8789SEd Tanous          chassisSubNode{std::string(chassisSubNode)},
4244e0d8789SEd Tanous          sensorTypes](const boost::system::error_code& ec,
4254e0d8789SEd Tanous                       const dbus::utility::MapperGetSubTreePathsResponse&
4264e0d8789SEd Tanous                           chassisPaths) mutable {
42762598e31SEd Tanous             BMCWEB_LOG_DEBUG("getChassis respHandler enter");
4281abe55efSEd Tanous             if (ec)
4291abe55efSEd Tanous             {
43062598e31SEd Tanous                 BMCWEB_LOG_ERROR("getChassis respHandler DBUS error: {}", ec);
4317f1cc26dSEd Tanous                 messages::internalError(asyncResp->res);
43208777fb0SLewanczyk, Dawid                 return;
43308777fb0SLewanczyk, Dawid             }
43449c53ac9SJohnathan Mantey             const std::string* chassisPath = nullptr;
43549c53ac9SJohnathan Mantey             for (const std::string& chassis : chassisPaths)
4361abe55efSEd Tanous             {
43728aa8de5SGeorge Liu                 sdbusplus::message::object_path path(chassis);
438f8fe53e7SEd Tanous                 std::string chassisName = path.filename();
43928aa8de5SGeorge Liu                 if (chassisName.empty())
4401abe55efSEd Tanous                 {
44162598e31SEd Tanous                     BMCWEB_LOG_ERROR("Failed to find '/' in {}", chassis);
442daf36e2eSEd Tanous                     continue;
443daf36e2eSEd Tanous                 }
4447f1cc26dSEd Tanous                 if (chassisName == chassisIdStr)
4451abe55efSEd Tanous                 {
44649c53ac9SJohnathan Mantey                     chassisPath = &chassis;
44749c53ac9SJohnathan Mantey                     break;
448daf36e2eSEd Tanous                 }
44949c53ac9SJohnathan Mantey             }
45049c53ac9SJohnathan Mantey             if (chassisPath == nullptr)
4511abe55efSEd Tanous             {
452bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res, "Chassis",
453bd79bce8SPatrick Williams                                            chassisIdStr);
45449c53ac9SJohnathan Mantey                 return;
4551abe55efSEd Tanous             }
4567f1cc26dSEd Tanous             populateChassisNode(asyncResp->res.jsonValue, chassisSubNode);
45708777fb0SLewanczyk, Dawid 
458ef4c65b7SEd Tanous             asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
459ef4c65b7SEd Tanous                 "/redfish/v1/Chassis/{}/{}", chassisIdStr, chassisSubNode);
46095a3ecadSAnthony Wilson 
4618fb49dd6SShawn McCarney             // Get the list of all sensors for this Chassis element
4628fb49dd6SShawn McCarney             std::string sensorPath = *chassisPath + "/all_sensors";
4636c3e9451SGeorge Liu             dbus::utility::getAssociationEndPoints(
4644e0d8789SEd Tanous                 sensorPath, [asyncResp, chassisSubNode, sensorTypes,
4654e0d8789SEd Tanous                              callback = std::forward<Callback>(callback)](
4668b24275dSEd Tanous                                 const boost::system::error_code& ec2,
4674e0d8789SEd Tanous                                 const dbus::utility::MapperEndPoints&
4684e0d8789SEd Tanous                                     nodeSensorList) mutable {
4698b24275dSEd Tanous                     if (ec2)
47049c53ac9SJohnathan Mantey                     {
4718b24275dSEd Tanous                         if (ec2.value() != EBADR)
47249c53ac9SJohnathan Mantey                         {
4737f1cc26dSEd Tanous                             messages::internalError(asyncResp->res);
47449c53ac9SJohnathan Mantey                             return;
47549c53ac9SJohnathan Mantey                         }
47649c53ac9SJohnathan Mantey                     }
477bd79bce8SPatrick Williams                     const std::shared_ptr<std::set<std::string>>
478bd79bce8SPatrick Williams                         culledSensorList =
479fe04d49cSNan Zhou                             std::make_shared<std::set<std::string>>();
480bd79bce8SPatrick Williams                     reduceSensorList(asyncResp->res, chassisSubNode,
481bd79bce8SPatrick Williams                                      sensorTypes, &nodeSensorList,
482bd79bce8SPatrick Williams                                      culledSensorList);
483bd79bce8SPatrick Williams                     BMCWEB_LOG_DEBUG("Finishing with {}",
484bd79bce8SPatrick Williams                                      culledSensorList->size());
48549c53ac9SJohnathan Mantey                     callback(culledSensorList);
4861e1e598dSJonathan Doman                 });
4877a1dbc48SGeorge Liu         });
48862598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassis exit");
48908777fb0SLewanczyk, Dawid }
49008777fb0SLewanczyk, Dawid 
49108777fb0SLewanczyk, Dawid /**
4921d7c0054SEd Tanous  * @brief Builds a json sensor representation of a sensor.
4931d7c0054SEd Tanous  * @param sensorName  The name of the sensor to be built
4941d7c0054SEd Tanous  * @param sensorType  The type (temperature, fan_tach, etc) of the sensor to
4951d7c0054SEd Tanous  * build
4968ece0e45SEd Tanous  * @param chassisSubNode The subnode (thermal, sensor, etc) of the sensor
4971d7c0054SEd Tanous  * @param interfacesDict  A dictionary of the interfaces and properties of said
4981d7c0054SEd Tanous  * interfaces to be built from
4991d7c0054SEd Tanous  * @param sensorJson  The json object to fill
5001d7c0054SEd Tanous  * @param inventoryItem D-Bus inventory item associated with the sensor.  Will
5011d7c0054SEd Tanous  * be nullptr if no associated inventory item was found.
5021d7c0054SEd Tanous  */
5031d7c0054SEd Tanous inline void objectInterfacesToJson(
5041d7c0054SEd Tanous     const std::string& sensorName, const std::string& sensorType,
5050c728b42SJanet Adkins     const sensor_utils::ChassisSubNode chassisSubNode,
50680f79a40SMichael Shen     const dbus::utility::DBusInterfacesMap& interfacesDict,
5071d7c0054SEd Tanous     nlohmann::json& sensorJson, InventoryItem* inventoryItem)
5081d7c0054SEd Tanous {
5091d7c0054SEd Tanous     for (const auto& [interface, valuesDict] : interfacesDict)
5101d7c0054SEd Tanous     {
511c9563608SJanet Adkins         sensor_utils::objectPropertiesToJson(
512c9563608SJanet Adkins             sensorName, sensorType, chassisSubNode, valuesDict, sensorJson,
513c9563608SJanet Adkins             inventoryItem);
5141d7c0054SEd Tanous     }
51562598e31SEd Tanous     BMCWEB_LOG_DEBUG("Added sensor {}", sensorName);
5161d7c0054SEd Tanous }
5171d7c0054SEd Tanous 
518b5a76932SEd Tanous inline void populateFanRedundancy(
519b5a76932SEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
5208bd25ccdSJames Feist {
521e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
522e99073f5SGeorge Liu         "xyz.openbmc_project.Control.FanRedundancy"};
523e99073f5SGeorge Liu     dbus::utility::getSubTree(
524e99073f5SGeorge Liu         "/xyz/openbmc_project/control", 2, interfaces,
525b9d36b47SEd Tanous         [sensorsAsyncResp](
526e99073f5SGeorge Liu             const boost::system::error_code& ec,
527b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& resp) {
5288bd25ccdSJames Feist             if (ec)
5298bd25ccdSJames Feist             {
5308bd25ccdSJames Feist                 return; // don't have to have this interface
5318bd25ccdSJames Feist             }
5326c3e9451SGeorge Liu             for (const std::pair<std::string, dbus::utility::MapperServiceMap>&
533e278c18fSEd Tanous                      pathPair : resp)
5348bd25ccdSJames Feist             {
535e278c18fSEd Tanous                 const std::string& path = pathPair.first;
536bd79bce8SPatrick Williams                 const dbus::utility::MapperServiceMap& objDict =
537bd79bce8SPatrick Williams                     pathPair.second;
5388bd25ccdSJames Feist                 if (objDict.empty())
5398bd25ccdSJames Feist                 {
5408bd25ccdSJames Feist                     continue; // this should be impossible
5418bd25ccdSJames Feist                 }
5428bd25ccdSJames Feist 
5438bd25ccdSJames Feist                 const std::string& owner = objDict.begin()->first;
5446c3e9451SGeorge Liu                 dbus::utility::getAssociationEndPoints(
5456c3e9451SGeorge Liu                     path + "/chassis",
5466c3e9451SGeorge Liu                     [path, owner, sensorsAsyncResp](
5478b24275dSEd Tanous                         const boost::system::error_code& ec2,
5486c3e9451SGeorge Liu                         const dbus::utility::MapperEndPoints& endpoints) {
5498b24275dSEd Tanous                         if (ec2)
5508bd25ccdSJames Feist                         {
5518bd25ccdSJames Feist                             return; // if they don't have an association we
5528bd25ccdSJames Feist                                     // can't tell what chassis is
5538bd25ccdSJames Feist                         }
5543544d2a7SEd Tanous                         auto found = std::ranges::find_if(
555bd79bce8SPatrick Williams                             endpoints,
556bd79bce8SPatrick Williams                             [sensorsAsyncResp](const std::string& entry) {
557bd79bce8SPatrick Williams                                 return entry.find(
558bd79bce8SPatrick Williams                                            sensorsAsyncResp->chassisId) !=
5598bd25ccdSJames Feist                                        std::string::npos;
5608bd25ccdSJames Feist                             });
5618bd25ccdSJames Feist 
5621e1e598dSJonathan Doman                         if (found == endpoints.end())
5638bd25ccdSJames Feist                         {
5648bd25ccdSJames Feist                             return;
5658bd25ccdSJames Feist                         }
566deae6a78SEd Tanous                         dbus::utility::getAllProperties(
56786d89ed7SKrzysztof Grobelny                             *crow::connections::systemBus, owner, path,
56886d89ed7SKrzysztof Grobelny                             "xyz.openbmc_project.Control.FanRedundancy",
5698bd25ccdSJames Feist                             [path, sensorsAsyncResp](
5708b24275dSEd Tanous                                 const boost::system::error_code& ec3,
57186d89ed7SKrzysztof Grobelny                                 const dbus::utility::DBusPropertiesMap& ret) {
5728b24275dSEd Tanous                                 if (ec3)
5738bd25ccdSJames Feist                                 {
5748bd25ccdSJames Feist                                     return; // don't have to have this
5758bd25ccdSJames Feist                                             // interface
5768bd25ccdSJames Feist                                 }
5778bd25ccdSJames Feist 
57886d89ed7SKrzysztof Grobelny                                 const uint8_t* allowedFailures = nullptr;
579bd79bce8SPatrick Williams                                 const std::vector<std::string>* collection =
580bd79bce8SPatrick Williams                                     nullptr;
58186d89ed7SKrzysztof Grobelny                                 const std::string* status = nullptr;
58286d89ed7SKrzysztof Grobelny 
583bd79bce8SPatrick Williams                                 const bool success =
584bd79bce8SPatrick Williams                                     sdbusplus::unpackPropertiesNoThrow(
58586d89ed7SKrzysztof Grobelny                                         dbus_utils::UnpackErrorPrinter(), ret,
586bd79bce8SPatrick Williams                                         "AllowedFailures", allowedFailures,
587bd79bce8SPatrick Williams                                         "Collection", collection, "Status",
588bd79bce8SPatrick Williams                                         status);
58986d89ed7SKrzysztof Grobelny 
59086d89ed7SKrzysztof Grobelny                                 if (!success)
59186d89ed7SKrzysztof Grobelny                                 {
59286d89ed7SKrzysztof Grobelny                                     messages::internalError(
59386d89ed7SKrzysztof Grobelny                                         sensorsAsyncResp->asyncResp->res);
59486d89ed7SKrzysztof Grobelny                                     return;
59586d89ed7SKrzysztof Grobelny                                 }
59686d89ed7SKrzysztof Grobelny 
597bd79bce8SPatrick Williams                                 if (allowedFailures == nullptr ||
598bd79bce8SPatrick Williams                                     collection == nullptr || status == nullptr)
5998bd25ccdSJames Feist                                 {
600bd79bce8SPatrick Williams                                     BMCWEB_LOG_ERROR(
601bd79bce8SPatrick Williams                                         "Invalid redundancy interface");
6028bd25ccdSJames Feist                                     messages::internalError(
6038d1b46d7Szhanghch05                                         sensorsAsyncResp->asyncResp->res);
6048bd25ccdSJames Feist                                     return;
6058bd25ccdSJames Feist                                 }
6068bd25ccdSJames Feist 
607bd79bce8SPatrick Williams                                 sdbusplus::message::object_path objectPath(
608bd79bce8SPatrick Williams                                     path);
60928aa8de5SGeorge Liu                                 std::string name = objectPath.filename();
61028aa8de5SGeorge Liu                                 if (name.empty())
6118bd25ccdSJames Feist                                 {
6128bd25ccdSJames Feist                                     // this should be impossible
6138bd25ccdSJames Feist                                     messages::internalError(
6148d1b46d7Szhanghch05                                         sensorsAsyncResp->asyncResp->res);
6158bd25ccdSJames Feist                                     return;
6168bd25ccdSJames Feist                                 }
61718f8f608SEd Tanous                                 std::ranges::replace(name, '_', ' ');
6188bd25ccdSJames Feist 
6198bd25ccdSJames Feist                                 std::string health;
6208bd25ccdSJames Feist 
62111ba3979SEd Tanous                                 if (status->ends_with("Full"))
6228bd25ccdSJames Feist                                 {
6238bd25ccdSJames Feist                                     health = "OK";
6248bd25ccdSJames Feist                                 }
62511ba3979SEd Tanous                                 else if (status->ends_with("Degraded"))
6268bd25ccdSJames Feist                                 {
6278bd25ccdSJames Feist                                     health = "Warning";
6288bd25ccdSJames Feist                                 }
6298bd25ccdSJames Feist                                 else
6308bd25ccdSJames Feist                                 {
6318bd25ccdSJames Feist                                     health = "Critical";
6328bd25ccdSJames Feist                                 }
6331476687dSEd Tanous                                 nlohmann::json::array_t redfishCollection;
6348bd25ccdSJames Feist                                 const auto& fanRedfish =
635bd79bce8SPatrick Williams                                     sensorsAsyncResp->asyncResp->res
636bd79bce8SPatrick Williams                                         .jsonValue["Fans"];
6378bd25ccdSJames Feist                                 for (const std::string& item : *collection)
6388bd25ccdSJames Feist                                 {
639bd79bce8SPatrick Williams                                     sdbusplus::message::object_path itemPath(
640bd79bce8SPatrick Williams                                         item);
6418a592810SEd Tanous                                     std::string itemName = itemPath.filename();
64228aa8de5SGeorge Liu                                     if (itemName.empty())
64328aa8de5SGeorge Liu                                     {
64428aa8de5SGeorge Liu                                         continue;
64528aa8de5SGeorge Liu                                     }
6468bd25ccdSJames Feist                                     /*
6478bd25ccdSJames Feist                                     todo(ed): merge patch that fixes the names
6488bd25ccdSJames Feist                                     std::replace(itemName.begin(),
6498bd25ccdSJames Feist                                                  itemName.end(), '_', ' ');*/
6503544d2a7SEd Tanous                                     auto schemaItem = std::ranges::find_if(
651bd79bce8SPatrick Williams                                         fanRedfish,
652bd79bce8SPatrick Williams                                         [itemName](const nlohmann::json& fan) {
6533e35c761SGeorge Liu                                             return fan["Name"] == itemName;
6548bd25ccdSJames Feist                                         });
6558bd25ccdSJames Feist                                     if (schemaItem != fanRedfish.end())
6568bd25ccdSJames Feist                                     {
6578a592810SEd Tanous                                         nlohmann::json::object_t collectionId;
6588a592810SEd Tanous                                         collectionId["@odata.id"] =
6591476687dSEd Tanous                                             (*schemaItem)["@odata.id"];
6601476687dSEd Tanous                                         redfishCollection.emplace_back(
6618a592810SEd Tanous                                             std::move(collectionId));
6628bd25ccdSJames Feist                                     }
6638bd25ccdSJames Feist                                     else
6648bd25ccdSJames Feist                                     {
665bd79bce8SPatrick Williams                                         BMCWEB_LOG_ERROR(
666bd79bce8SPatrick Williams                                             "failed to find fan in schema");
6678bd25ccdSJames Feist                                         messages::internalError(
6688d1b46d7Szhanghch05                                             sensorsAsyncResp->asyncResp->res);
6698bd25ccdSJames Feist                                         return;
6708bd25ccdSJames Feist                                     }
6718bd25ccdSJames Feist                                 }
6728bd25ccdSJames Feist 
673bd79bce8SPatrick Williams                                 size_t minNumNeeded =
674bd79bce8SPatrick Williams                                     collection->empty()
67526f6976fSEd Tanous                                         ? 0
676bd79bce8SPatrick Williams                                         : collection->size() - *allowedFailures;
677bd79bce8SPatrick Williams                                 nlohmann::json& jResp =
678bd79bce8SPatrick Williams                                     sensorsAsyncResp->asyncResp->res
6798bd25ccdSJames Feist                                         .jsonValue["Redundancy"];
6801476687dSEd Tanous 
6811476687dSEd Tanous                                 nlohmann::json::object_t redundancy;
682bd79bce8SPatrick Williams                                 boost::urls::url url = boost::urls::format(
683bd79bce8SPatrick Williams                                     "/redfish/v1/Chassis/{}/{}",
684ef4c65b7SEd Tanous                                     sensorsAsyncResp->chassisId,
685eddfc437SWilly Tu                                     sensorsAsyncResp->chassisSubNode);
686bd79bce8SPatrick Williams                                 url.set_fragment(
687bd79bce8SPatrick Williams                                     ("/Redundancy"_json_pointer / jResp.size())
688eddfc437SWilly Tu                                         .to_string());
689eddfc437SWilly Tu                                 redundancy["@odata.id"] = std::move(url);
690bd79bce8SPatrick Williams                                 redundancy["@odata.type"] =
691bd79bce8SPatrick Williams                                     "#Redundancy.v1_3_2.Redundancy";
6921476687dSEd Tanous                                 redundancy["MinNumNeeded"] = minNumNeeded;
693bd79bce8SPatrick Williams                                 redundancy["Mode"] =
694bd79bce8SPatrick Williams                                     redundancy::RedundancyType::NPlusM;
6951476687dSEd Tanous                                 redundancy["Name"] = name;
6961476687dSEd Tanous                                 redundancy["RedundancySet"] = redfishCollection;
6971476687dSEd Tanous                                 redundancy["Status"]["Health"] = health;
698bd79bce8SPatrick Williams                                 redundancy["Status"]["State"] =
699bd79bce8SPatrick Williams                                     resource::State::Enabled;
7001476687dSEd Tanous 
701b2ba3072SPatrick Williams                                 jResp.emplace_back(std::move(redundancy));
70286d89ed7SKrzysztof Grobelny                             });
7031e1e598dSJonathan Doman                     });
7048bd25ccdSJames Feist             }
705e99073f5SGeorge Liu         });
7068bd25ccdSJames Feist }
7078bd25ccdSJames Feist 
708*504af5a0SPatrick Williams inline void sortJSONResponse(
709*504af5a0SPatrick Williams     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
71049c53ac9SJohnathan Mantey {
7118d1b46d7Szhanghch05     nlohmann::json& response = sensorsAsyncResp->asyncResp->res.jsonValue;
71249c53ac9SJohnathan Mantey     std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
7130c728b42SJanet Adkins     if (sensorsAsyncResp->chassisSubNode == sensors::powerNodeStr)
71449c53ac9SJohnathan Mantey     {
71549c53ac9SJohnathan Mantey         sensorHeaders = {"Voltages", "PowerSupplies"};
71649c53ac9SJohnathan Mantey     }
71749c53ac9SJohnathan Mantey     for (const std::string& sensorGroup : sensorHeaders)
71849c53ac9SJohnathan Mantey     {
71949c53ac9SJohnathan Mantey         nlohmann::json::iterator entry = response.find(sensorGroup);
7204e196b9aSEd Tanous         if (entry == response.end())
72149c53ac9SJohnathan Mantey         {
7224e196b9aSEd Tanous             continue;
7234e196b9aSEd Tanous         }
7244e196b9aSEd Tanous         nlohmann::json::array_t* arr =
7254e196b9aSEd Tanous             entry->get_ptr<nlohmann::json::array_t*>();
7264e196b9aSEd Tanous         if (arr == nullptr)
7274e196b9aSEd Tanous         {
7284e196b9aSEd Tanous             continue;
7294e196b9aSEd Tanous         }
7304e196b9aSEd Tanous         json_util::sortJsonArrayByKey(*arr, "Name");
73149c53ac9SJohnathan Mantey 
73249c53ac9SJohnathan Mantey         // add the index counts to the end of each entry
73349c53ac9SJohnathan Mantey         size_t count = 0;
73449c53ac9SJohnathan Mantey         for (nlohmann::json& sensorJson : *entry)
73549c53ac9SJohnathan Mantey         {
73649c53ac9SJohnathan Mantey             nlohmann::json::iterator odata = sensorJson.find("@odata.id");
73749c53ac9SJohnathan Mantey             if (odata == sensorJson.end())
73849c53ac9SJohnathan Mantey             {
73949c53ac9SJohnathan Mantey                 continue;
74049c53ac9SJohnathan Mantey             }
74149c53ac9SJohnathan Mantey             std::string* value = odata->get_ptr<std::string*>();
74249c53ac9SJohnathan Mantey             if (value != nullptr)
74349c53ac9SJohnathan Mantey             {
744eddfc437SWilly Tu                 *value += "/" + std::to_string(count);
7453e35c761SGeorge Liu                 sensorJson["MemberId"] = std::to_string(count);
74649c53ac9SJohnathan Mantey                 count++;
74781ce609eSEd Tanous                 sensorsAsyncResp->updateUri(sensorJson["Name"], *value);
74849c53ac9SJohnathan Mantey             }
74949c53ac9SJohnathan Mantey         }
75049c53ac9SJohnathan Mantey     }
75149c53ac9SJohnathan Mantey }
75249c53ac9SJohnathan Mantey 
75308777fb0SLewanczyk, Dawid /**
754adc4f0dbSShawn McCarney  * @brief Finds the inventory item with the specified object path.
755adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
756adc4f0dbSShawn McCarney  * @param invItemObjPath D-Bus object path of inventory item.
757adc4f0dbSShawn McCarney  * @return Inventory item within vector, or nullptr if no match found.
7588fb49dd6SShawn McCarney  */
75923a21a1cSEd Tanous inline InventoryItem* findInventoryItem(
760b5a76932SEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
761adc4f0dbSShawn McCarney     const std::string& invItemObjPath)
7628fb49dd6SShawn McCarney {
763adc4f0dbSShawn McCarney     for (InventoryItem& inventoryItem : *inventoryItems)
7648fb49dd6SShawn McCarney     {
765adc4f0dbSShawn McCarney         if (inventoryItem.objectPath == invItemObjPath)
7668fb49dd6SShawn McCarney         {
767adc4f0dbSShawn McCarney             return &inventoryItem;
7688fb49dd6SShawn McCarney         }
7698fb49dd6SShawn McCarney     }
7708fb49dd6SShawn McCarney     return nullptr;
7718fb49dd6SShawn McCarney }
7728fb49dd6SShawn McCarney 
7738fb49dd6SShawn McCarney /**
774adc4f0dbSShawn McCarney  * @brief Finds the inventory item associated with the specified sensor.
775adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
776adc4f0dbSShawn McCarney  * @param sensorObjPath D-Bus object path of sensor.
777adc4f0dbSShawn McCarney  * @return Inventory item within vector, or nullptr if no match found.
7788fb49dd6SShawn McCarney  */
77923a21a1cSEd Tanous inline InventoryItem* findInventoryItemForSensor(
780b5a76932SEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
781adc4f0dbSShawn McCarney     const std::string& sensorObjPath)
782adc4f0dbSShawn McCarney {
783adc4f0dbSShawn McCarney     for (InventoryItem& inventoryItem : *inventoryItems)
784adc4f0dbSShawn McCarney     {
785db0d36efSEd Tanous         if (inventoryItem.sensors.contains(sensorObjPath))
786adc4f0dbSShawn McCarney         {
787adc4f0dbSShawn McCarney             return &inventoryItem;
788adc4f0dbSShawn McCarney         }
789adc4f0dbSShawn McCarney     }
790adc4f0dbSShawn McCarney     return nullptr;
791adc4f0dbSShawn McCarney }
792adc4f0dbSShawn McCarney 
793adc4f0dbSShawn McCarney /**
794d500549bSAnthony Wilson  * @brief Finds the inventory item associated with the specified led path.
795d500549bSAnthony Wilson  * @param inventoryItems D-Bus inventory items associated with sensors.
796d500549bSAnthony Wilson  * @param ledObjPath D-Bus object path of led.
797d500549bSAnthony Wilson  * @return Inventory item within vector, or nullptr if no match found.
798d500549bSAnthony Wilson  */
799bd79bce8SPatrick Williams inline InventoryItem* findInventoryItemForLed(
800bd79bce8SPatrick Williams     std::vector<InventoryItem>& inventoryItems, const std::string& ledObjPath)
801d500549bSAnthony Wilson {
802d500549bSAnthony Wilson     for (InventoryItem& inventoryItem : inventoryItems)
803d500549bSAnthony Wilson     {
804d500549bSAnthony Wilson         if (inventoryItem.ledObjectPath == ledObjPath)
805d500549bSAnthony Wilson         {
806d500549bSAnthony Wilson             return &inventoryItem;
807d500549bSAnthony Wilson         }
808d500549bSAnthony Wilson     }
809d500549bSAnthony Wilson     return nullptr;
810d500549bSAnthony Wilson }
811d500549bSAnthony Wilson 
812d500549bSAnthony Wilson /**
813adc4f0dbSShawn McCarney  * @brief Adds inventory item and associated sensor to specified vector.
814adc4f0dbSShawn McCarney  *
815adc4f0dbSShawn McCarney  * Adds a new InventoryItem to the vector if necessary.  Searches for an
816adc4f0dbSShawn McCarney  * existing InventoryItem with the specified object path.  If not found, one is
817adc4f0dbSShawn McCarney  * added to the vector.
818adc4f0dbSShawn McCarney  *
819adc4f0dbSShawn McCarney  * Next, the specified sensor is added to the set of sensors associated with the
820adc4f0dbSShawn McCarney  * InventoryItem.
821adc4f0dbSShawn McCarney  *
822adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
823adc4f0dbSShawn McCarney  * @param invItemObjPath D-Bus object path of inventory item.
824adc4f0dbSShawn McCarney  * @param sensorObjPath D-Bus object path of sensor
825adc4f0dbSShawn McCarney  */
826b5a76932SEd Tanous inline void addInventoryItem(
827b5a76932SEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
828b5a76932SEd Tanous     const std::string& invItemObjPath, const std::string& sensorObjPath)
829adc4f0dbSShawn McCarney {
830adc4f0dbSShawn McCarney     // Look for inventory item in vector
831bd79bce8SPatrick Williams     InventoryItem* inventoryItem =
832bd79bce8SPatrick Williams         findInventoryItem(inventoryItems, invItemObjPath);
833adc4f0dbSShawn McCarney 
834adc4f0dbSShawn McCarney     // If inventory item doesn't exist in vector, add it
835adc4f0dbSShawn McCarney     if (inventoryItem == nullptr)
836adc4f0dbSShawn McCarney     {
837adc4f0dbSShawn McCarney         inventoryItems->emplace_back(invItemObjPath);
838adc4f0dbSShawn McCarney         inventoryItem = &(inventoryItems->back());
839adc4f0dbSShawn McCarney     }
840adc4f0dbSShawn McCarney 
841adc4f0dbSShawn McCarney     // Add sensor to set of sensors associated with inventory item
842adc4f0dbSShawn McCarney     inventoryItem->sensors.emplace(sensorObjPath);
843adc4f0dbSShawn McCarney }
844adc4f0dbSShawn McCarney 
845adc4f0dbSShawn McCarney /**
846adc4f0dbSShawn McCarney  * @brief Stores D-Bus data in the specified inventory item.
847adc4f0dbSShawn McCarney  *
848adc4f0dbSShawn McCarney  * Finds D-Bus data in the specified map of interfaces.  Stores the data in the
849adc4f0dbSShawn McCarney  * specified InventoryItem.
850adc4f0dbSShawn McCarney  *
851adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
852adc4f0dbSShawn McCarney  * response.
853adc4f0dbSShawn McCarney  *
854adc4f0dbSShawn McCarney  * @param inventoryItem Inventory item where data will be stored.
855adc4f0dbSShawn McCarney  * @param interfacesDict Map containing D-Bus interfaces and their properties
856adc4f0dbSShawn McCarney  * for the specified inventory item.
857adc4f0dbSShawn McCarney  */
85823a21a1cSEd Tanous inline void storeInventoryItemData(
859adc4f0dbSShawn McCarney     InventoryItem& inventoryItem,
86080f79a40SMichael Shen     const dbus::utility::DBusInterfacesMap& interfacesDict)
8618fb49dd6SShawn McCarney {
862adc4f0dbSShawn McCarney     // Get properties from Inventory.Item interface
863711ac7a9SEd Tanous 
8649eb808c1SEd Tanous     for (const auto& [interface, values] : interfacesDict)
8658fb49dd6SShawn McCarney     {
866711ac7a9SEd Tanous         if (interface == "xyz.openbmc_project.Inventory.Item")
8678fb49dd6SShawn McCarney         {
8689eb808c1SEd Tanous             for (const auto& [name, dbusValue] : values)
869711ac7a9SEd Tanous             {
870711ac7a9SEd Tanous                 if (name == "Present")
871711ac7a9SEd Tanous                 {
872711ac7a9SEd Tanous                     const bool* value = std::get_if<bool>(&dbusValue);
873adc4f0dbSShawn McCarney                     if (value != nullptr)
8748fb49dd6SShawn McCarney                     {
875adc4f0dbSShawn McCarney                         inventoryItem.isPresent = *value;
8768fb49dd6SShawn McCarney                     }
8778fb49dd6SShawn McCarney                 }
8788fb49dd6SShawn McCarney             }
879711ac7a9SEd Tanous         }
880adc4f0dbSShawn McCarney         // Check if Inventory.Item.PowerSupply interface is present
881711ac7a9SEd Tanous 
882711ac7a9SEd Tanous         if (interface == "xyz.openbmc_project.Inventory.Item.PowerSupply")
8838fb49dd6SShawn McCarney         {
884adc4f0dbSShawn McCarney             inventoryItem.isPowerSupply = true;
8858fb49dd6SShawn McCarney         }
886adc4f0dbSShawn McCarney 
887adc4f0dbSShawn McCarney         // Get properties from Inventory.Decorator.Asset interface
888711ac7a9SEd Tanous         if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
889adc4f0dbSShawn McCarney         {
8909eb808c1SEd Tanous             for (const auto& [name, dbusValue] : values)
891711ac7a9SEd Tanous             {
892711ac7a9SEd Tanous                 if (name == "Manufacturer")
893adc4f0dbSShawn McCarney                 {
894adc4f0dbSShawn McCarney                     const std::string* value =
895711ac7a9SEd Tanous                         std::get_if<std::string>(&dbusValue);
896adc4f0dbSShawn McCarney                     if (value != nullptr)
897adc4f0dbSShawn McCarney                     {
898adc4f0dbSShawn McCarney                         inventoryItem.manufacturer = *value;
899adc4f0dbSShawn McCarney                     }
900adc4f0dbSShawn McCarney                 }
901711ac7a9SEd Tanous                 if (name == "Model")
902adc4f0dbSShawn McCarney                 {
903adc4f0dbSShawn McCarney                     const std::string* value =
904711ac7a9SEd Tanous                         std::get_if<std::string>(&dbusValue);
905adc4f0dbSShawn McCarney                     if (value != nullptr)
906adc4f0dbSShawn McCarney                     {
907adc4f0dbSShawn McCarney                         inventoryItem.model = *value;
908adc4f0dbSShawn McCarney                     }
909adc4f0dbSShawn McCarney                 }
910711ac7a9SEd Tanous                 if (name == "SerialNumber")
911adc4f0dbSShawn McCarney                 {
912adc4f0dbSShawn McCarney                     const std::string* value =
913711ac7a9SEd Tanous                         std::get_if<std::string>(&dbusValue);
914adc4f0dbSShawn McCarney                     if (value != nullptr)
915adc4f0dbSShawn McCarney                     {
916adc4f0dbSShawn McCarney                         inventoryItem.serialNumber = *value;
917adc4f0dbSShawn McCarney                     }
918adc4f0dbSShawn McCarney                 }
919711ac7a9SEd Tanous                 if (name == "PartNumber")
920711ac7a9SEd Tanous                 {
921711ac7a9SEd Tanous                     const std::string* value =
922711ac7a9SEd Tanous                         std::get_if<std::string>(&dbusValue);
923711ac7a9SEd Tanous                     if (value != nullptr)
924711ac7a9SEd Tanous                     {
925711ac7a9SEd Tanous                         inventoryItem.partNumber = *value;
926711ac7a9SEd Tanous                     }
927711ac7a9SEd Tanous                 }
928711ac7a9SEd Tanous             }
929adc4f0dbSShawn McCarney         }
930adc4f0dbSShawn McCarney 
931711ac7a9SEd Tanous         if (interface ==
932711ac7a9SEd Tanous             "xyz.openbmc_project.State.Decorator.OperationalStatus")
933adc4f0dbSShawn McCarney         {
9349eb808c1SEd Tanous             for (const auto& [name, dbusValue] : values)
935adc4f0dbSShawn McCarney             {
936711ac7a9SEd Tanous                 if (name == "Functional")
937711ac7a9SEd Tanous                 {
938711ac7a9SEd Tanous                     const bool* value = std::get_if<bool>(&dbusValue);
939adc4f0dbSShawn McCarney                     if (value != nullptr)
940adc4f0dbSShawn McCarney                     {
941adc4f0dbSShawn McCarney                         inventoryItem.isFunctional = *value;
9428fb49dd6SShawn McCarney                     }
9438fb49dd6SShawn McCarney                 }
9448fb49dd6SShawn McCarney             }
9458fb49dd6SShawn McCarney         }
946711ac7a9SEd Tanous     }
947711ac7a9SEd Tanous }
9488fb49dd6SShawn McCarney 
9498fb49dd6SShawn McCarney /**
950adc4f0dbSShawn McCarney  * @brief Gets D-Bus data for inventory items associated with sensors.
9518fb49dd6SShawn McCarney  *
952adc4f0dbSShawn McCarney  * Uses the specified connections (services) to obtain D-Bus data for inventory
953adc4f0dbSShawn McCarney  * items associated with sensors.  Stores the resulting data in the
954adc4f0dbSShawn McCarney  * inventoryItems vector.
9558fb49dd6SShawn McCarney  *
956adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
957adc4f0dbSShawn McCarney  * response.
958adc4f0dbSShawn McCarney  *
959adc4f0dbSShawn McCarney  * Finds the inventory item data asynchronously.  Invokes callback when data has
960adc4f0dbSShawn McCarney  * been obtained.
961adc4f0dbSShawn McCarney  *
962adc4f0dbSShawn McCarney  * The callback must have the following signature:
963adc4f0dbSShawn McCarney  *   @code
964d500549bSAnthony Wilson  *   callback(void)
965adc4f0dbSShawn McCarney  *   @endcode
966adc4f0dbSShawn McCarney  *
967adc4f0dbSShawn McCarney  * This function is called recursively, obtaining data asynchronously from one
968adc4f0dbSShawn McCarney  * connection in each call.  This ensures the callback is not invoked until the
969adc4f0dbSShawn McCarney  * last asynchronous function has completed.
9708fb49dd6SShawn McCarney  *
9718fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
972adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
973adc4f0dbSShawn McCarney  * @param invConnections Connections that provide data for the inventory items.
9748fb49dd6SShawn McCarney  * implements ObjectManager.
975adc4f0dbSShawn McCarney  * @param callback Callback to invoke when inventory data has been obtained.
976adc4f0dbSShawn McCarney  * @param invConnectionsIndex Current index in invConnections.  Only specified
977adc4f0dbSShawn McCarney  * in recursive calls to this function.
9788fb49dd6SShawn McCarney  */
979adc4f0dbSShawn McCarney template <typename Callback>
9804ff0f1f4SEd Tanous void getInventoryItemsData(
981daadfb2eSEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
982daadfb2eSEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
983daadfb2eSEd Tanous     const std::shared_ptr<std::set<std::string>>& invConnections,
984daadfb2eSEd Tanous     Callback&& callback, size_t invConnectionsIndex = 0)
9858fb49dd6SShawn McCarney {
98662598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemsData enter");
9878fb49dd6SShawn McCarney 
988adc4f0dbSShawn McCarney     // If no more connections left, call callback
989adc4f0dbSShawn McCarney     if (invConnectionsIndex >= invConnections->size())
9908fb49dd6SShawn McCarney     {
991d500549bSAnthony Wilson         callback();
99262598e31SEd Tanous         BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
993adc4f0dbSShawn McCarney         return;
994adc4f0dbSShawn McCarney     }
995adc4f0dbSShawn McCarney 
996adc4f0dbSShawn McCarney     // Get inventory item data from current connection
997fe04d49cSNan Zhou     auto it = invConnections->begin();
998fe04d49cSNan Zhou     std::advance(it, invConnectionsIndex);
999adc4f0dbSShawn McCarney     if (it != invConnections->end())
1000adc4f0dbSShawn McCarney     {
1001adc4f0dbSShawn McCarney         const std::string& invConnection = *it;
1002adc4f0dbSShawn McCarney 
10035eb468daSGeorge Liu         // Get all object paths and their interfaces for current connection
10045eb468daSGeorge Liu         sdbusplus::message::object_path path("/xyz/openbmc_project/inventory");
10055eb468daSGeorge Liu         dbus::utility::getManagedObjects(
10065eb468daSGeorge Liu             invConnection, path,
10075eb468daSGeorge Liu             [sensorsAsyncResp, inventoryItems, invConnections,
10088cb2c024SEd Tanous              callback = std::forward<Callback>(callback), invConnectionsIndex](
10095e7e2dc5SEd Tanous                 const boost::system::error_code& ec,
10104e0d8789SEd Tanous                 const dbus::utility::ManagedObjectType& resp) mutable {
101162598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler enter");
10128fb49dd6SShawn McCarney                 if (ec)
10138fb49dd6SShawn McCarney                 {
101462598e31SEd Tanous                     BMCWEB_LOG_ERROR(
101562598e31SEd Tanous                         "getInventoryItemsData respHandler DBus error {}", ec);
10168d1b46d7Szhanghch05                     messages::internalError(sensorsAsyncResp->asyncResp->res);
10178fb49dd6SShawn McCarney                     return;
10188fb49dd6SShawn McCarney                 }
10198fb49dd6SShawn McCarney 
10208fb49dd6SShawn McCarney                 // Loop through returned object paths
10218fb49dd6SShawn McCarney                 for (const auto& objDictEntry : resp)
10228fb49dd6SShawn McCarney                 {
10238fb49dd6SShawn McCarney                     const std::string& objPath =
10248fb49dd6SShawn McCarney                         static_cast<const std::string&>(objDictEntry.first);
10258fb49dd6SShawn McCarney 
1026bd79bce8SPatrick Williams                     // If this object path is one of the specified inventory
1027bd79bce8SPatrick Williams                     // items
1028bd79bce8SPatrick Williams                     InventoryItem* inventoryItem =
1029bd79bce8SPatrick Williams                         findInventoryItem(inventoryItems, objPath);
1030adc4f0dbSShawn McCarney                     if (inventoryItem != nullptr)
10318fb49dd6SShawn McCarney                     {
1032adc4f0dbSShawn McCarney                         // Store inventory data in InventoryItem
1033bd79bce8SPatrick Williams                         storeInventoryItemData(*inventoryItem,
1034bd79bce8SPatrick Williams                                                objDictEntry.second);
10358fb49dd6SShawn McCarney                     }
10368fb49dd6SShawn McCarney                 }
10378fb49dd6SShawn McCarney 
1038adc4f0dbSShawn McCarney                 // Recurse to get inventory item data from next connection
1039adc4f0dbSShawn McCarney                 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1040d0090733SEd Tanous                                       invConnections, std::move(callback),
1041d0090733SEd Tanous                                       invConnectionsIndex + 1);
1042adc4f0dbSShawn McCarney 
104362598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler exit");
10445eb468daSGeorge Liu             });
10458fb49dd6SShawn McCarney     }
10468fb49dd6SShawn McCarney 
104762598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
10488fb49dd6SShawn McCarney }
10498fb49dd6SShawn McCarney 
10508fb49dd6SShawn McCarney /**
1051adc4f0dbSShawn McCarney  * @brief Gets connections that provide D-Bus data for inventory items.
10528fb49dd6SShawn McCarney  *
1053adc4f0dbSShawn McCarney  * Gets the D-Bus connections (services) that provide data for the inventory
1054adc4f0dbSShawn McCarney  * items that are associated with sensors.
10558fb49dd6SShawn McCarney  *
10568fb49dd6SShawn McCarney  * Finds the connections asynchronously.  Invokes callback when information has
10578fb49dd6SShawn McCarney  * been obtained.
10588fb49dd6SShawn McCarney  *
10598fb49dd6SShawn McCarney  * The callback must have the following signature:
10608fb49dd6SShawn McCarney  *   @code
1061fe04d49cSNan Zhou  *   callback(std::shared_ptr<std::set<std::string>> invConnections)
10628fb49dd6SShawn McCarney  *   @endcode
10638fb49dd6SShawn McCarney  *
10648fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
1065adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
10668fb49dd6SShawn McCarney  * @param callback Callback to invoke when connections have been obtained.
10678fb49dd6SShawn McCarney  */
10688fb49dd6SShawn McCarney template <typename Callback>
10694ff0f1f4SEd Tanous void getInventoryItemsConnections(
1070b5a76932SEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1071b5a76932SEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
10728fb49dd6SShawn McCarney     Callback&& callback)
10738fb49dd6SShawn McCarney {
107462598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemsConnections enter");
10758fb49dd6SShawn McCarney 
10768fb49dd6SShawn McCarney     const std::string path = "/xyz/openbmc_project/inventory";
1077e99073f5SGeorge Liu     constexpr std::array<std::string_view, 4> interfaces = {
10788fb49dd6SShawn McCarney         "xyz.openbmc_project.Inventory.Item",
1079adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Item.PowerSupply",
1080adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Decorator.Asset",
10818fb49dd6SShawn McCarney         "xyz.openbmc_project.State.Decorator.OperationalStatus"};
10828fb49dd6SShawn McCarney 
1083e99073f5SGeorge Liu     // Make call to ObjectMapper to find all inventory items
1084e99073f5SGeorge Liu     dbus::utility::getSubTree(
1085e99073f5SGeorge Liu         path, 0, interfaces,
10868cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), sensorsAsyncResp,
1087002d39b4SEd Tanous          inventoryItems](
1088e99073f5SGeorge Liu             const boost::system::error_code& ec,
10894e0d8789SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
1090e99073f5SGeorge Liu             // Response handler for parsing output from GetSubTree
109162598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler enter");
10928fb49dd6SShawn McCarney             if (ec)
10938fb49dd6SShawn McCarney             {
10948d1b46d7Szhanghch05                 messages::internalError(sensorsAsyncResp->asyncResp->res);
109562598e31SEd Tanous                 BMCWEB_LOG_ERROR(
1096bd79bce8SPatrick Williams                     "getInventoryItemsConnections respHandler DBus error {}",
1097bd79bce8SPatrick Williams                     ec);
10988fb49dd6SShawn McCarney                 return;
10998fb49dd6SShawn McCarney             }
11008fb49dd6SShawn McCarney 
11018fb49dd6SShawn McCarney             // Make unique list of connections for desired inventory items
1102fe04d49cSNan Zhou             std::shared_ptr<std::set<std::string>> invConnections =
1103fe04d49cSNan Zhou                 std::make_shared<std::set<std::string>>();
11048fb49dd6SShawn McCarney 
11058fb49dd6SShawn McCarney             // Loop through objects from GetSubTree
1106bd79bce8SPatrick Williams             for (const std::pair<std::string,
1107bd79bce8SPatrick Williams                                  std::vector<std::pair<
1108bd79bce8SPatrick Williams                                      std::string, std::vector<std::string>>>>&
11098fb49dd6SShawn McCarney                      object : subtree)
11108fb49dd6SShawn McCarney             {
1111adc4f0dbSShawn McCarney                 // Check if object path is one of the specified inventory items
11128fb49dd6SShawn McCarney                 const std::string& objPath = object.first;
1113adc4f0dbSShawn McCarney                 if (findInventoryItem(inventoryItems, objPath) != nullptr)
11148fb49dd6SShawn McCarney                 {
11158fb49dd6SShawn McCarney                     // Store all connections to inventory item
11168fb49dd6SShawn McCarney                     for (const std::pair<std::string, std::vector<std::string>>&
11178fb49dd6SShawn McCarney                              objData : object.second)
11188fb49dd6SShawn McCarney                     {
11198fb49dd6SShawn McCarney                         const std::string& invConnection = objData.first;
11208fb49dd6SShawn McCarney                         invConnections->insert(invConnection);
11218fb49dd6SShawn McCarney                     }
11228fb49dd6SShawn McCarney                 }
11238fb49dd6SShawn McCarney             }
1124d500549bSAnthony Wilson 
11258fb49dd6SShawn McCarney             callback(invConnections);
112662598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler exit");
1127e99073f5SGeorge Liu         });
112862598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemsConnections exit");
11298fb49dd6SShawn McCarney }
11308fb49dd6SShawn McCarney 
11318fb49dd6SShawn McCarney /**
1132adc4f0dbSShawn McCarney  * @brief Gets associations from sensors to inventory items.
11338fb49dd6SShawn McCarney  *
11348fb49dd6SShawn McCarney  * Looks for ObjectMapper associations from the specified sensors to related
1135d500549bSAnthony Wilson  * inventory items. Then finds the associations from those inventory items to
1136d500549bSAnthony Wilson  * their LEDs, if any.
11378fb49dd6SShawn McCarney  *
11388fb49dd6SShawn McCarney  * Finds the inventory items asynchronously.  Invokes callback when information
11398fb49dd6SShawn McCarney  * has been obtained.
11408fb49dd6SShawn McCarney  *
11418fb49dd6SShawn McCarney  * The callback must have the following signature:
11428fb49dd6SShawn McCarney  *   @code
1143adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
11448fb49dd6SShawn McCarney  *   @endcode
11458fb49dd6SShawn McCarney  *
11468fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
11478fb49dd6SShawn McCarney  * @param sensorNames All sensors within the current chassis.
11488fb49dd6SShawn McCarney  * implements ObjectManager.
11498fb49dd6SShawn McCarney  * @param callback Callback to invoke when inventory items have been obtained.
11508fb49dd6SShawn McCarney  */
11518fb49dd6SShawn McCarney template <typename Callback>
11524ff0f1f4SEd Tanous void getInventoryItemAssociations(
1153b5a76932SEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1154fe04d49cSNan Zhou     const std::shared_ptr<std::set<std::string>>& sensorNames,
11558fb49dd6SShawn McCarney     Callback&& callback)
11568fb49dd6SShawn McCarney {
115762598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemAssociations enter");
11588fb49dd6SShawn McCarney 
11595eb468daSGeorge Liu     // Call GetManagedObjects on the ObjectMapper to get all associations
11605eb468daSGeorge Liu     sdbusplus::message::object_path path("/");
11615eb468daSGeorge Liu     dbus::utility::getManagedObjects(
11625eb468daSGeorge Liu         "xyz.openbmc_project.ObjectMapper", path,
11638cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), sensorsAsyncResp,
11645e7e2dc5SEd Tanous          sensorNames](const boost::system::error_code& ec,
11654e0d8789SEd Tanous                       const dbus::utility::ManagedObjectType& resp) mutable {
116662598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler enter");
11678fb49dd6SShawn McCarney             if (ec)
11688fb49dd6SShawn McCarney             {
116962598e31SEd Tanous                 BMCWEB_LOG_ERROR(
1170bd79bce8SPatrick Williams                     "getInventoryItemAssociations respHandler DBus error {}",
1171bd79bce8SPatrick Williams                     ec);
11728d1b46d7Szhanghch05                 messages::internalError(sensorsAsyncResp->asyncResp->res);
11738fb49dd6SShawn McCarney                 return;
11748fb49dd6SShawn McCarney             }
11758fb49dd6SShawn McCarney 
1176adc4f0dbSShawn McCarney             // Create vector to hold list of inventory items
1177adc4f0dbSShawn McCarney             std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1178adc4f0dbSShawn McCarney                 std::make_shared<std::vector<InventoryItem>>();
1179adc4f0dbSShawn McCarney 
11808fb49dd6SShawn McCarney             // Loop through returned object paths
11818fb49dd6SShawn McCarney             std::string sensorAssocPath;
11828fb49dd6SShawn McCarney             sensorAssocPath.reserve(128); // avoid memory allocations
11838fb49dd6SShawn McCarney             for (const auto& objDictEntry : resp)
11848fb49dd6SShawn McCarney             {
11858fb49dd6SShawn McCarney                 const std::string& objPath =
11868fb49dd6SShawn McCarney                     static_cast<const std::string&>(objDictEntry.first);
11878fb49dd6SShawn McCarney 
1188bd79bce8SPatrick Williams                 // If path is inventory association for one of the specified
1189bd79bce8SPatrick Williams                 // sensors
11908fb49dd6SShawn McCarney                 for (const std::string& sensorName : *sensorNames)
11918fb49dd6SShawn McCarney                 {
11928fb49dd6SShawn McCarney                     sensorAssocPath = sensorName;
11938fb49dd6SShawn McCarney                     sensorAssocPath += "/inventory";
11948fb49dd6SShawn McCarney                     if (objPath == sensorAssocPath)
11958fb49dd6SShawn McCarney                     {
11968fb49dd6SShawn McCarney                         // Get Association interface for object path
1197bd79bce8SPatrick Williams                         for (const auto& [interface, values] :
1198bd79bce8SPatrick Williams                              objDictEntry.second)
11998fb49dd6SShawn McCarney                         {
1200711ac7a9SEd Tanous                             if (interface == "xyz.openbmc_project.Association")
1201711ac7a9SEd Tanous                             {
1202711ac7a9SEd Tanous                                 for (const auto& [valueName, value] : values)
1203711ac7a9SEd Tanous                                 {
1204711ac7a9SEd Tanous                                     if (valueName == "endpoints")
12058fb49dd6SShawn McCarney                                     {
1206bd79bce8SPatrick Williams                                         const std::vector<std::string>*
1207bd79bce8SPatrick Williams                                             endpoints = std::get_if<
1208bd79bce8SPatrick Williams                                                 std::vector<std::string>>(
1209711ac7a9SEd Tanous                                                 &value);
1210711ac7a9SEd Tanous                                         if ((endpoints != nullptr) &&
1211711ac7a9SEd Tanous                                             !endpoints->empty())
12128fb49dd6SShawn McCarney                                         {
1213adc4f0dbSShawn McCarney                                             // Add inventory item to vector
1214adc4f0dbSShawn McCarney                                             const std::string& invItemPath =
1215adc4f0dbSShawn McCarney                                                 endpoints->front();
1216711ac7a9SEd Tanous                                             addInventoryItem(inventoryItems,
1217711ac7a9SEd Tanous                                                              invItemPath,
1218adc4f0dbSShawn McCarney                                                              sensorName);
12198fb49dd6SShawn McCarney                                         }
12208fb49dd6SShawn McCarney                                     }
12218fb49dd6SShawn McCarney                                 }
1222711ac7a9SEd Tanous                             }
1223711ac7a9SEd Tanous                         }
12248fb49dd6SShawn McCarney                         break;
12258fb49dd6SShawn McCarney                     }
12268fb49dd6SShawn McCarney                 }
12278fb49dd6SShawn McCarney             }
12288fb49dd6SShawn McCarney 
1229d500549bSAnthony Wilson             // Now loop through the returned object paths again, this time to
1230d500549bSAnthony Wilson             // find the leds associated with the inventory items we just found
1231d500549bSAnthony Wilson             std::string inventoryAssocPath;
1232d500549bSAnthony Wilson             inventoryAssocPath.reserve(128); // avoid memory allocations
1233d500549bSAnthony Wilson             for (const auto& objDictEntry : resp)
1234d500549bSAnthony Wilson             {
1235d500549bSAnthony Wilson                 const std::string& objPath =
1236d500549bSAnthony Wilson                     static_cast<const std::string&>(objDictEntry.first);
1237d500549bSAnthony Wilson 
1238d500549bSAnthony Wilson                 for (InventoryItem& inventoryItem : *inventoryItems)
1239d500549bSAnthony Wilson                 {
1240d500549bSAnthony Wilson                     inventoryAssocPath = inventoryItem.objectPath;
1241d500549bSAnthony Wilson                     inventoryAssocPath += "/leds";
1242d500549bSAnthony Wilson                     if (objPath == inventoryAssocPath)
1243d500549bSAnthony Wilson                     {
1244bd79bce8SPatrick Williams                         for (const auto& [interface, values] :
1245bd79bce8SPatrick Williams                              objDictEntry.second)
1246d500549bSAnthony Wilson                         {
1247711ac7a9SEd Tanous                             if (interface == "xyz.openbmc_project.Association")
1248711ac7a9SEd Tanous                             {
1249711ac7a9SEd Tanous                                 for (const auto& [valueName, value] : values)
1250711ac7a9SEd Tanous                                 {
1251711ac7a9SEd Tanous                                     if (valueName == "endpoints")
1252d500549bSAnthony Wilson                                     {
1253bd79bce8SPatrick Williams                                         const std::vector<std::string>*
1254bd79bce8SPatrick Williams                                             endpoints = std::get_if<
1255bd79bce8SPatrick Williams                                                 std::vector<std::string>>(
1256711ac7a9SEd Tanous                                                 &value);
1257711ac7a9SEd Tanous                                         if ((endpoints != nullptr) &&
1258711ac7a9SEd Tanous                                             !endpoints->empty())
1259d500549bSAnthony Wilson                                         {
1260711ac7a9SEd Tanous                                             // Add inventory item to vector
1261d500549bSAnthony Wilson                                             // Store LED path in inventory item
1262711ac7a9SEd Tanous                                             const std::string& ledPath =
1263711ac7a9SEd Tanous                                                 endpoints->front();
1264bd79bce8SPatrick Williams                                             inventoryItem.ledObjectPath =
1265bd79bce8SPatrick Williams                                                 ledPath;
1266d500549bSAnthony Wilson                                         }
1267d500549bSAnthony Wilson                                     }
1268d500549bSAnthony Wilson                                 }
1269711ac7a9SEd Tanous                             }
1270711ac7a9SEd Tanous                         }
1271711ac7a9SEd Tanous 
1272d500549bSAnthony Wilson                         break;
1273d500549bSAnthony Wilson                     }
1274d500549bSAnthony Wilson                 }
1275d500549bSAnthony Wilson             }
1276adc4f0dbSShawn McCarney             callback(inventoryItems);
127762598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler exit");
12785eb468daSGeorge Liu         });
12798fb49dd6SShawn McCarney 
128062598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemAssociations exit");
12818fb49dd6SShawn McCarney }
12828fb49dd6SShawn McCarney 
12838fb49dd6SShawn McCarney /**
1284d500549bSAnthony Wilson  * @brief Gets D-Bus data for inventory item leds associated with sensors.
1285d500549bSAnthony Wilson  *
1286d500549bSAnthony Wilson  * Uses the specified connections (services) to obtain D-Bus data for inventory
1287d500549bSAnthony Wilson  * item leds associated with sensors.  Stores the resulting data in the
1288d500549bSAnthony Wilson  * inventoryItems vector.
1289d500549bSAnthony Wilson  *
1290d500549bSAnthony Wilson  * This data is later used to provide sensor property values in the JSON
1291d500549bSAnthony Wilson  * response.
1292d500549bSAnthony Wilson  *
1293d500549bSAnthony Wilson  * Finds the inventory item led data asynchronously.  Invokes callback when data
1294d500549bSAnthony Wilson  * has been obtained.
1295d500549bSAnthony Wilson  *
1296d500549bSAnthony Wilson  * The callback must have the following signature:
1297d500549bSAnthony Wilson  *   @code
129842cbe538SGunnar Mills  *   callback()
1299d500549bSAnthony Wilson  *   @endcode
1300d500549bSAnthony Wilson  *
1301d500549bSAnthony Wilson  * This function is called recursively, obtaining data asynchronously from one
1302d500549bSAnthony Wilson  * connection in each call.  This ensures the callback is not invoked until the
1303d500549bSAnthony Wilson  * last asynchronous function has completed.
1304d500549bSAnthony Wilson  *
1305d500549bSAnthony Wilson  * @param sensorsAsyncResp Pointer to object holding response data.
1306d500549bSAnthony Wilson  * @param inventoryItems D-Bus inventory items associated with sensors.
1307d500549bSAnthony Wilson  * @param ledConnections Connections that provide data for the inventory leds.
1308d500549bSAnthony Wilson  * @param callback Callback to invoke when inventory data has been obtained.
1309d500549bSAnthony Wilson  * @param ledConnectionsIndex Current index in ledConnections.  Only specified
1310d500549bSAnthony Wilson  * in recursive calls to this function.
1311d500549bSAnthony Wilson  */
1312d500549bSAnthony Wilson template <typename Callback>
1313d500549bSAnthony Wilson void getInventoryLedData(
1314daadfb2eSEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1315daadfb2eSEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
1316daadfb2eSEd Tanous     const std::shared_ptr<std::map<std::string, std::string>>& ledConnections,
1317d500549bSAnthony Wilson     Callback&& callback, size_t ledConnectionsIndex = 0)
1318d500549bSAnthony Wilson {
131962598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryLedData enter");
1320d500549bSAnthony Wilson 
1321d500549bSAnthony Wilson     // If no more connections left, call callback
1322d500549bSAnthony Wilson     if (ledConnectionsIndex >= ledConnections->size())
1323d500549bSAnthony Wilson     {
132442cbe538SGunnar Mills         callback();
132562598e31SEd Tanous         BMCWEB_LOG_DEBUG("getInventoryLedData exit");
1326d500549bSAnthony Wilson         return;
1327d500549bSAnthony Wilson     }
1328d500549bSAnthony Wilson 
1329d500549bSAnthony Wilson     // Get inventory item data from current connection
1330fe04d49cSNan Zhou     auto it = ledConnections->begin();
1331fe04d49cSNan Zhou     std::advance(it, ledConnectionsIndex);
1332d500549bSAnthony Wilson     if (it != ledConnections->end())
1333d500549bSAnthony Wilson     {
1334d500549bSAnthony Wilson         const std::string& ledPath = (*it).first;
1335d500549bSAnthony Wilson         const std::string& ledConnection = (*it).second;
1336d500549bSAnthony Wilson         // Response handler for Get State property
13371e1e598dSJonathan Doman         auto respHandler =
13381e1e598dSJonathan Doman             [sensorsAsyncResp, inventoryItems, ledConnections, ledPath,
13394e0d8789SEd Tanous              callback = std::forward<Callback>(callback),
13404e0d8789SEd Tanous              ledConnectionsIndex](const boost::system::error_code& ec,
13414e0d8789SEd Tanous                                   const std::string& state) mutable {
134262598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler enter");
1343d500549bSAnthony Wilson                 if (ec)
1344d500549bSAnthony Wilson                 {
134562598e31SEd Tanous                     BMCWEB_LOG_ERROR(
134662598e31SEd Tanous                         "getInventoryLedData respHandler DBus error {}", ec);
13478d1b46d7Szhanghch05                     messages::internalError(sensorsAsyncResp->asyncResp->res);
1348d500549bSAnthony Wilson                     return;
1349d500549bSAnthony Wilson                 }
1350d500549bSAnthony Wilson 
135162598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Led state: {}", state);
1352d500549bSAnthony Wilson                 // Find inventory item with this LED object path
1353d500549bSAnthony Wilson                 InventoryItem* inventoryItem =
1354d500549bSAnthony Wilson                     findInventoryItemForLed(*inventoryItems, ledPath);
1355d500549bSAnthony Wilson                 if (inventoryItem != nullptr)
1356d500549bSAnthony Wilson                 {
1357d500549bSAnthony Wilson                     // Store LED state in InventoryItem
135811ba3979SEd Tanous                     if (state.ends_with("On"))
1359d500549bSAnthony Wilson                     {
1360c9563608SJanet Adkins                         inventoryItem->ledState = sensor_utils::LedState::ON;
1361d500549bSAnthony Wilson                     }
136211ba3979SEd Tanous                     else if (state.ends_with("Blink"))
1363d500549bSAnthony Wilson                     {
1364c9563608SJanet Adkins                         inventoryItem->ledState = sensor_utils::LedState::BLINK;
1365d500549bSAnthony Wilson                     }
136611ba3979SEd Tanous                     else if (state.ends_with("Off"))
1367d500549bSAnthony Wilson                     {
1368c9563608SJanet Adkins                         inventoryItem->ledState = sensor_utils::LedState::OFF;
1369d500549bSAnthony Wilson                     }
1370d500549bSAnthony Wilson                     else
1371d500549bSAnthony Wilson                     {
1372c9563608SJanet Adkins                         inventoryItem->ledState =
1373c9563608SJanet Adkins                             sensor_utils::LedState::UNKNOWN;
1374d500549bSAnthony Wilson                     }
1375d500549bSAnthony Wilson                 }
1376d500549bSAnthony Wilson 
1377d500549bSAnthony Wilson                 // Recurse to get LED data from next connection
1378d500549bSAnthony Wilson                 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1379d500549bSAnthony Wilson                                     ledConnections, std::move(callback),
1380d500549bSAnthony Wilson                                     ledConnectionsIndex + 1);
1381d500549bSAnthony Wilson 
138262598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler exit");
1383d500549bSAnthony Wilson             };
1384d500549bSAnthony Wilson 
1385d500549bSAnthony Wilson         // Get the State property for the current LED
1386deae6a78SEd Tanous         dbus::utility::getProperty<std::string>(
1387deae6a78SEd Tanous             ledConnection, ledPath, "xyz.openbmc_project.Led.Physical", "State",
13881e1e598dSJonathan Doman             std::move(respHandler));
1389d500549bSAnthony Wilson     }
1390d500549bSAnthony Wilson 
139162598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryLedData exit");
1392d500549bSAnthony Wilson }
1393d500549bSAnthony Wilson 
1394d500549bSAnthony Wilson /**
1395d500549bSAnthony Wilson  * @brief Gets LED data for LEDs associated with given inventory items.
1396d500549bSAnthony Wilson  *
1397d500549bSAnthony Wilson  * Gets the D-Bus connections (services) that provide LED data for the LEDs
1398d500549bSAnthony Wilson  * associated with the specified inventory items.  Then gets the LED data from
1399d500549bSAnthony Wilson  * each connection and stores it in the inventory item.
1400d500549bSAnthony Wilson  *
1401d500549bSAnthony Wilson  * This data is later used to provide sensor property values in the JSON
1402d500549bSAnthony Wilson  * response.
1403d500549bSAnthony Wilson  *
1404d500549bSAnthony Wilson  * Finds the LED data asynchronously.  Invokes callback when information has
1405d500549bSAnthony Wilson  * been obtained.
1406d500549bSAnthony Wilson  *
1407d500549bSAnthony Wilson  * The callback must have the following signature:
1408d500549bSAnthony Wilson  *   @code
140942cbe538SGunnar Mills  *   callback()
1410d500549bSAnthony Wilson  *   @endcode
1411d500549bSAnthony Wilson  *
1412d500549bSAnthony Wilson  * @param sensorsAsyncResp Pointer to object holding response data.
1413d500549bSAnthony Wilson  * @param inventoryItems D-Bus inventory items associated with sensors.
1414d500549bSAnthony Wilson  * @param callback Callback to invoke when inventory items have been obtained.
1415d500549bSAnthony Wilson  */
1416d500549bSAnthony Wilson template <typename Callback>
1417d500549bSAnthony Wilson void getInventoryLeds(
1418daadfb2eSEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1419daadfb2eSEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
1420d500549bSAnthony Wilson     Callback&& callback)
1421d500549bSAnthony Wilson {
142262598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryLeds enter");
1423d500549bSAnthony Wilson 
1424d500549bSAnthony Wilson     const std::string path = "/xyz/openbmc_project";
1425e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
1426d500549bSAnthony Wilson         "xyz.openbmc_project.Led.Physical"};
1427d500549bSAnthony Wilson 
1428e99073f5SGeorge Liu     // Make call to ObjectMapper to find all inventory items
1429e99073f5SGeorge Liu     dbus::utility::getSubTree(
1430e99073f5SGeorge Liu         path, 0, interfaces,
14318cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), sensorsAsyncResp,
1432002d39b4SEd Tanous          inventoryItems](
1433e99073f5SGeorge Liu             const boost::system::error_code& ec,
14344e0d8789SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
1435e99073f5SGeorge Liu             // Response handler for parsing output from GetSubTree
143662598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryLeds respHandler enter");
1437d500549bSAnthony Wilson             if (ec)
1438d500549bSAnthony Wilson             {
14398d1b46d7Szhanghch05                 messages::internalError(sensorsAsyncResp->asyncResp->res);
1440bd79bce8SPatrick Williams                 BMCWEB_LOG_ERROR("getInventoryLeds respHandler DBus error {}",
1441bd79bce8SPatrick Williams                                  ec);
1442d500549bSAnthony Wilson                 return;
1443d500549bSAnthony Wilson             }
1444d500549bSAnthony Wilson 
1445d500549bSAnthony Wilson             // Build map of LED object paths to connections
1446fe04d49cSNan Zhou             std::shared_ptr<std::map<std::string, std::string>> ledConnections =
1447fe04d49cSNan Zhou                 std::make_shared<std::map<std::string, std::string>>();
1448d500549bSAnthony Wilson 
1449d500549bSAnthony Wilson             // Loop through objects from GetSubTree
1450bd79bce8SPatrick Williams             for (const std::pair<std::string,
1451bd79bce8SPatrick Williams                                  std::vector<std::pair<
1452bd79bce8SPatrick Williams                                      std::string, std::vector<std::string>>>>&
1453d500549bSAnthony Wilson                      object : subtree)
1454d500549bSAnthony Wilson             {
1455bd79bce8SPatrick Williams                 // Check if object path is LED for one of the specified
1456bd79bce8SPatrick Williams                 // inventory items
1457d500549bSAnthony Wilson                 const std::string& ledPath = object.first;
1458bd79bce8SPatrick Williams                 if (findInventoryItemForLed(*inventoryItems, ledPath) !=
1459bd79bce8SPatrick Williams                     nullptr)
1460d500549bSAnthony Wilson                 {
1461d500549bSAnthony Wilson                     // Add mapping from ledPath to connection
1462bd79bce8SPatrick Williams                     const std::string& connection =
1463bd79bce8SPatrick Williams                         object.second.begin()->first;
1464d500549bSAnthony Wilson                     (*ledConnections)[ledPath] = connection;
1465bd79bce8SPatrick Williams                     BMCWEB_LOG_DEBUG("Added mapping {} -> {}", ledPath,
1466bd79bce8SPatrick Williams                                      connection);
1467d500549bSAnthony Wilson                 }
1468d500549bSAnthony Wilson             }
1469d500549bSAnthony Wilson 
1470bd79bce8SPatrick Williams             getInventoryLedData(sensorsAsyncResp, inventoryItems,
1471bd79bce8SPatrick Williams                                 ledConnections, std::move(callback));
147262598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryLeds respHandler exit");
1473e99073f5SGeorge Liu         });
147462598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryLeds exit");
1475d500549bSAnthony Wilson }
1476d500549bSAnthony Wilson 
1477d500549bSAnthony Wilson /**
147842cbe538SGunnar Mills  * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent
147942cbe538SGunnar Mills  *
148042cbe538SGunnar Mills  * Uses the specified connections (services) (currently assumes just one) to
148142cbe538SGunnar Mills  * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in
148242cbe538SGunnar Mills  * the inventoryItems vector. Only stores data in Power Supply inventoryItems.
148342cbe538SGunnar Mills  *
148442cbe538SGunnar Mills  * This data is later used to provide sensor property values in the JSON
148542cbe538SGunnar Mills  * response.
148642cbe538SGunnar Mills  *
148742cbe538SGunnar Mills  * Finds the Power Supply Attributes data asynchronously.  Invokes callback
148842cbe538SGunnar Mills  * when data has been obtained.
148942cbe538SGunnar Mills  *
149042cbe538SGunnar Mills  * The callback must have the following signature:
149142cbe538SGunnar Mills  *   @code
149242cbe538SGunnar Mills  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
149342cbe538SGunnar Mills  *   @endcode
149442cbe538SGunnar Mills  *
149542cbe538SGunnar Mills  * @param sensorsAsyncResp Pointer to object holding response data.
149642cbe538SGunnar Mills  * @param inventoryItems D-Bus inventory items associated with sensors.
149742cbe538SGunnar Mills  * @param psAttributesConnections Connections that provide data for the Power
149842cbe538SGunnar Mills  *        Supply Attributes
149942cbe538SGunnar Mills  * @param callback Callback to invoke when data has been obtained.
150042cbe538SGunnar Mills  */
150142cbe538SGunnar Mills template <typename Callback>
150242cbe538SGunnar Mills void getPowerSupplyAttributesData(
1503b5a76932SEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1504daadfb2eSEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
1505fe04d49cSNan Zhou     const std::map<std::string, std::string>& psAttributesConnections,
150642cbe538SGunnar Mills     Callback&& callback)
150742cbe538SGunnar Mills {
150862598e31SEd Tanous     BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData enter");
150942cbe538SGunnar Mills 
151042cbe538SGunnar Mills     if (psAttributesConnections.empty())
151142cbe538SGunnar Mills     {
151262598e31SEd Tanous         BMCWEB_LOG_DEBUG("Can't find PowerSupplyAttributes, no connections!");
151342cbe538SGunnar Mills         callback(inventoryItems);
151442cbe538SGunnar Mills         return;
151542cbe538SGunnar Mills     }
151642cbe538SGunnar Mills 
151742cbe538SGunnar Mills     // Assuming just one connection (service) for now
1518fe04d49cSNan Zhou     auto it = psAttributesConnections.begin();
151942cbe538SGunnar Mills 
152042cbe538SGunnar Mills     const std::string& psAttributesPath = (*it).first;
152142cbe538SGunnar Mills     const std::string& psAttributesConnection = (*it).second;
152242cbe538SGunnar Mills 
152342cbe538SGunnar Mills     // Response handler for Get DeratingFactor property
15245a39f77aSPatrick Williams     auto respHandler = [sensorsAsyncResp, inventoryItems,
15258cb2c024SEd Tanous                         callback = std::forward<Callback>(callback)](
15265a39f77aSPatrick Williams                            const boost::system::error_code& ec,
15274e0d8789SEd Tanous                            uint32_t value) mutable {
152862598e31SEd Tanous         BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler enter");
152942cbe538SGunnar Mills         if (ec)
153042cbe538SGunnar Mills         {
153162598e31SEd Tanous             BMCWEB_LOG_ERROR(
153262598e31SEd Tanous                 "getPowerSupplyAttributesData respHandler DBus error {}", ec);
15338d1b46d7Szhanghch05             messages::internalError(sensorsAsyncResp->asyncResp->res);
153442cbe538SGunnar Mills             return;
153542cbe538SGunnar Mills         }
153642cbe538SGunnar Mills 
153762598e31SEd Tanous         BMCWEB_LOG_DEBUG("PS EfficiencyPercent value: {}", value);
153842cbe538SGunnar Mills         // Store value in Power Supply Inventory Items
153942cbe538SGunnar Mills         for (InventoryItem& inventoryItem : *inventoryItems)
154042cbe538SGunnar Mills         {
154155f79e6fSEd Tanous             if (inventoryItem.isPowerSupply)
154242cbe538SGunnar Mills             {
154342cbe538SGunnar Mills                 inventoryItem.powerSupplyEfficiencyPercent =
15441e1e598dSJonathan Doman                     static_cast<int>(value);
154542cbe538SGunnar Mills             }
154642cbe538SGunnar Mills         }
154742cbe538SGunnar Mills 
154862598e31SEd Tanous         BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler exit");
154942cbe538SGunnar Mills         callback(inventoryItems);
155042cbe538SGunnar Mills     };
155142cbe538SGunnar Mills 
155242cbe538SGunnar Mills     // Get the DeratingFactor property for the PowerSupplyAttributes
155342cbe538SGunnar Mills     // Currently only property on the interface/only one we care about
1554deae6a78SEd Tanous     dbus::utility::getProperty<uint32_t>(
1555deae6a78SEd Tanous         psAttributesConnection, psAttributesPath,
15561e1e598dSJonathan Doman         "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
15571e1e598dSJonathan Doman         std::move(respHandler));
155842cbe538SGunnar Mills 
155962598e31SEd Tanous     BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData exit");
156042cbe538SGunnar Mills }
156142cbe538SGunnar Mills 
156242cbe538SGunnar Mills /**
156342cbe538SGunnar Mills  * @brief Gets the Power Supply Attributes such as EfficiencyPercent
156442cbe538SGunnar Mills  *
156542cbe538SGunnar Mills  * Gets the D-Bus connection (service) that provides Power Supply Attributes
156642cbe538SGunnar Mills  * data. Then gets the Power Supply Attributes data from the connection
156742cbe538SGunnar Mills  * (currently just assumes 1 connection) and stores the data in the inventory
156842cbe538SGunnar Mills  * item.
156942cbe538SGunnar Mills  *
157042cbe538SGunnar Mills  * This data is later used to provide sensor property values in the JSON
157142cbe538SGunnar Mills  * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish.
157242cbe538SGunnar Mills  *
157342cbe538SGunnar Mills  * Finds the Power Supply Attributes data asynchronously. Invokes callback
157442cbe538SGunnar Mills  * when information has been obtained.
157542cbe538SGunnar Mills  *
157642cbe538SGunnar Mills  * The callback must have the following signature:
157742cbe538SGunnar Mills  *   @code
157842cbe538SGunnar Mills  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
157942cbe538SGunnar Mills  *   @endcode
158042cbe538SGunnar Mills  *
158142cbe538SGunnar Mills  * @param sensorsAsyncResp Pointer to object holding response data.
158242cbe538SGunnar Mills  * @param inventoryItems D-Bus inventory items associated with sensors.
158342cbe538SGunnar Mills  * @param callback Callback to invoke when data has been obtained.
158442cbe538SGunnar Mills  */
158542cbe538SGunnar Mills template <typename Callback>
158642cbe538SGunnar Mills void getPowerSupplyAttributes(
1587daadfb2eSEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1588daadfb2eSEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
158942cbe538SGunnar Mills     Callback&& callback)
159042cbe538SGunnar Mills {
159162598e31SEd Tanous     BMCWEB_LOG_DEBUG("getPowerSupplyAttributes enter");
159242cbe538SGunnar Mills 
159342cbe538SGunnar Mills     // Only need the power supply attributes when the Power Schema
15940c728b42SJanet Adkins     if (sensorsAsyncResp->chassisSubNode != sensors::powerNodeStr)
159542cbe538SGunnar Mills     {
159662598e31SEd Tanous         BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit since not Power");
159742cbe538SGunnar Mills         callback(inventoryItems);
159842cbe538SGunnar Mills         return;
159942cbe538SGunnar Mills     }
160042cbe538SGunnar Mills 
1601e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
160242cbe538SGunnar Mills         "xyz.openbmc_project.Control.PowerSupplyAttributes"};
160342cbe538SGunnar Mills 
1604e99073f5SGeorge Liu     // Make call to ObjectMapper to find the PowerSupplyAttributes service
1605e99073f5SGeorge Liu     dbus::utility::getSubTree(
1606e99073f5SGeorge Liu         "/xyz/openbmc_project", 0, interfaces,
16078cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), sensorsAsyncResp,
1608b9d36b47SEd Tanous          inventoryItems](
1609e99073f5SGeorge Liu             const boost::system::error_code& ec,
16104e0d8789SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
1611e99073f5SGeorge Liu             // Response handler for parsing output from GetSubTree
161262598e31SEd Tanous             BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler enter");
161342cbe538SGunnar Mills             if (ec)
161442cbe538SGunnar Mills             {
16158d1b46d7Szhanghch05                 messages::internalError(sensorsAsyncResp->asyncResp->res);
161662598e31SEd Tanous                 BMCWEB_LOG_ERROR(
161762598e31SEd Tanous                     "getPowerSupplyAttributes respHandler DBus error {}", ec);
161842cbe538SGunnar Mills                 return;
161942cbe538SGunnar Mills             }
162026f6976fSEd Tanous             if (subtree.empty())
162142cbe538SGunnar Mills             {
162262598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
162342cbe538SGunnar Mills                 callback(inventoryItems);
162442cbe538SGunnar Mills                 return;
162542cbe538SGunnar Mills             }
162642cbe538SGunnar Mills 
162742cbe538SGunnar Mills             // Currently we only support 1 power supply attribute, use this for
162842cbe538SGunnar Mills             // all the power supplies. Build map of object path to connection.
162942cbe538SGunnar Mills             // Assume just 1 connection and 1 path for now.
1630fe04d49cSNan Zhou             std::map<std::string, std::string> psAttributesConnections;
163142cbe538SGunnar Mills 
163242cbe538SGunnar Mills             if (subtree[0].first.empty() || subtree[0].second.empty())
163342cbe538SGunnar Mills             {
163462598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
163542cbe538SGunnar Mills                 callback(inventoryItems);
163642cbe538SGunnar Mills                 return;
163742cbe538SGunnar Mills             }
163842cbe538SGunnar Mills 
163942cbe538SGunnar Mills             const std::string& psAttributesPath = subtree[0].first;
164042cbe538SGunnar Mills             const std::string& connection = subtree[0].second.begin()->first;
164142cbe538SGunnar Mills 
164242cbe538SGunnar Mills             if (connection.empty())
164342cbe538SGunnar Mills             {
164462598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
164542cbe538SGunnar Mills                 callback(inventoryItems);
164642cbe538SGunnar Mills                 return;
164742cbe538SGunnar Mills             }
164842cbe538SGunnar Mills 
164942cbe538SGunnar Mills             psAttributesConnections[psAttributesPath] = connection;
165062598e31SEd Tanous             BMCWEB_LOG_DEBUG("Added mapping {} -> {}", psAttributesPath,
165162598e31SEd Tanous                              connection);
165242cbe538SGunnar Mills 
165342cbe538SGunnar Mills             getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems,
165442cbe538SGunnar Mills                                          psAttributesConnections,
165542cbe538SGunnar Mills                                          std::move(callback));
165662598e31SEd Tanous             BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler exit");
1657e99073f5SGeorge Liu         });
165862598e31SEd Tanous     BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit");
165942cbe538SGunnar Mills }
166042cbe538SGunnar Mills 
166142cbe538SGunnar Mills /**
1662adc4f0dbSShawn McCarney  * @brief Gets inventory items associated with sensors.
16638fb49dd6SShawn McCarney  *
16648fb49dd6SShawn McCarney  * Finds the inventory items that are associated with the specified sensors.
1665adc4f0dbSShawn McCarney  * Then gets D-Bus data for the inventory items, such as presence and VPD.
16668fb49dd6SShawn McCarney  *
1667adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
1668adc4f0dbSShawn McCarney  * response.
16698fb49dd6SShawn McCarney  *
1670adc4f0dbSShawn McCarney  * Finds the inventory items asynchronously.  Invokes callback when the
1671adc4f0dbSShawn McCarney  * inventory items have been obtained.
1672adc4f0dbSShawn McCarney  *
1673adc4f0dbSShawn McCarney  * The callback must have the following signature:
1674adc4f0dbSShawn McCarney  *   @code
1675adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1676adc4f0dbSShawn McCarney  *   @endcode
16778fb49dd6SShawn McCarney  *
16788fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
16798fb49dd6SShawn McCarney  * @param sensorNames All sensors within the current chassis.
16808fb49dd6SShawn McCarney  * implements ObjectManager.
1681adc4f0dbSShawn McCarney  * @param callback Callback to invoke when inventory items have been obtained.
16828fb49dd6SShawn McCarney  */
1683adc4f0dbSShawn McCarney template <typename Callback>
1684*504af5a0SPatrick Williams inline void getInventoryItems(
1685*504af5a0SPatrick Williams     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1686daadfb2eSEd Tanous     const std::shared_ptr<std::set<std::string>>& sensorNames,
1687adc4f0dbSShawn McCarney     Callback&& callback)
16888fb49dd6SShawn McCarney {
168962598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItems enter");
1690adc4f0dbSShawn McCarney     auto getInventoryItemAssociationsCb =
16918cb2c024SEd Tanous         [sensorsAsyncResp, callback = std::forward<Callback>(callback)](
1692daadfb2eSEd Tanous             const std::shared_ptr<std::vector<InventoryItem>>&
16934e0d8789SEd Tanous                 inventoryItems) mutable {
169462598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb enter");
16958fb49dd6SShawn McCarney             auto getInventoryItemsConnectionsCb =
1696d0090733SEd Tanous                 [sensorsAsyncResp, inventoryItems,
16974e0d8789SEd Tanous                  callback = std::forward<Callback>(callback)](
1698daadfb2eSEd Tanous                     const std::shared_ptr<std::set<std::string>>&
16994e0d8789SEd Tanous                         invConnections) mutable {
170062598e31SEd Tanous                     BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb enter");
1701bd79bce8SPatrick Williams                     auto getInventoryItemsDataCb =
1702bd79bce8SPatrick Williams                         [sensorsAsyncResp, inventoryItems,
17034e0d8789SEd Tanous                          callback =
17044e0d8789SEd Tanous                              std::forward<Callback>(callback)]() mutable {
170562598e31SEd Tanous                             BMCWEB_LOG_DEBUG("getInventoryItemsDataCb enter");
170642cbe538SGunnar Mills 
1707bd79bce8SPatrick Williams                             auto getInventoryLedsCb =
1708bd79bce8SPatrick Williams                                 [sensorsAsyncResp, inventoryItems,
17094e0d8789SEd Tanous                                  callback = std::forward<Callback>(
17104e0d8789SEd Tanous                                      callback)]() mutable {
1711bd79bce8SPatrick Williams                                     BMCWEB_LOG_DEBUG(
1712bd79bce8SPatrick Williams                                         "getInventoryLedsCb enter");
1713bd79bce8SPatrick Williams                                     // Find Power Supply Attributes and get the
1714bd79bce8SPatrick Williams                                     // data
1715bd79bce8SPatrick Williams                                     getPowerSupplyAttributes(
1716bd79bce8SPatrick Williams                                         sensorsAsyncResp, inventoryItems,
171742cbe538SGunnar Mills                                         std::move(callback));
171862598e31SEd Tanous                                     BMCWEB_LOG_DEBUG("getInventoryLedsCb exit");
171942cbe538SGunnar Mills                                 };
172042cbe538SGunnar Mills 
1721d500549bSAnthony Wilson                             // Find led connections and get the data
1722d500549bSAnthony Wilson                             getInventoryLeds(sensorsAsyncResp, inventoryItems,
172342cbe538SGunnar Mills                                              std::move(getInventoryLedsCb));
172462598e31SEd Tanous                             BMCWEB_LOG_DEBUG("getInventoryItemsDataCb exit");
1725d500549bSAnthony Wilson                         };
17268fb49dd6SShawn McCarney 
1727adc4f0dbSShawn McCarney                     // Get inventory item data from connections
1728adc4f0dbSShawn McCarney                     getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1729d0090733SEd Tanous                                           invConnections,
1730d500549bSAnthony Wilson                                           std::move(getInventoryItemsDataCb));
173162598e31SEd Tanous                     BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb exit");
17328fb49dd6SShawn McCarney                 };
17338fb49dd6SShawn McCarney 
1734adc4f0dbSShawn McCarney             // Get connections that provide inventory item data
1735bd79bce8SPatrick Williams             getInventoryItemsConnections(
1736bd79bce8SPatrick Williams                 sensorsAsyncResp, inventoryItems,
17378fb49dd6SShawn McCarney                 std::move(getInventoryItemsConnectionsCb));
173862598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb exit");
17398fb49dd6SShawn McCarney         };
17408fb49dd6SShawn McCarney 
1741adc4f0dbSShawn McCarney     // Get associations from sensors to inventory items
1742d0090733SEd Tanous     getInventoryItemAssociations(sensorsAsyncResp, sensorNames,
1743adc4f0dbSShawn McCarney                                  std::move(getInventoryItemAssociationsCb));
174462598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItems exit");
1745adc4f0dbSShawn McCarney }
1746adc4f0dbSShawn McCarney 
1747adc4f0dbSShawn McCarney /**
1748adc4f0dbSShawn McCarney  * @brief Returns JSON PowerSupply object for the specified inventory item.
1749adc4f0dbSShawn McCarney  *
1750adc4f0dbSShawn McCarney  * Searches for a JSON PowerSupply object that matches the specified inventory
1751adc4f0dbSShawn McCarney  * item.  If one is not found, a new PowerSupply object is added to the JSON
1752adc4f0dbSShawn McCarney  * array.
1753adc4f0dbSShawn McCarney  *
1754adc4f0dbSShawn McCarney  * Multiple sensors are often associated with one power supply inventory item.
1755adc4f0dbSShawn McCarney  * As a result, multiple sensor values are stored in one JSON PowerSupply
1756adc4f0dbSShawn McCarney  * object.
1757adc4f0dbSShawn McCarney  *
1758adc4f0dbSShawn McCarney  * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1759adc4f0dbSShawn McCarney  * @param inventoryItem Inventory item for the power supply.
1760adc4f0dbSShawn McCarney  * @param chassisId Chassis that contains the power supply.
1761adc4f0dbSShawn McCarney  * @return JSON PowerSupply object for the specified inventory item.
1762adc4f0dbSShawn McCarney  */
176323a21a1cSEd Tanous inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
1764adc4f0dbSShawn McCarney                                       const InventoryItem& inventoryItem,
1765adc4f0dbSShawn McCarney                                       const std::string& chassisId)
1766adc4f0dbSShawn McCarney {
176718f8f608SEd Tanous     std::string nameS;
17686f4bd290SAlexander Hansen     nameS.resize(inventoryItem.name.size());
176918f8f608SEd Tanous     std::ranges::replace_copy(inventoryItem.name, nameS.begin(), '_', ' ');
1770adc4f0dbSShawn McCarney     // Check if matching PowerSupply object already exists in JSON array
1771adc4f0dbSShawn McCarney     for (nlohmann::json& powerSupply : powerSupplyArray)
1772adc4f0dbSShawn McCarney     {
177318f8f608SEd Tanous         nlohmann::json::iterator nameIt = powerSupply.find("Name");
177418f8f608SEd Tanous         if (nameIt == powerSupply.end())
177518f8f608SEd Tanous         {
177618f8f608SEd Tanous             continue;
177718f8f608SEd Tanous         }
177818f8f608SEd Tanous         const std::string* name = nameIt->get_ptr<std::string*>();
177918f8f608SEd Tanous         if (name == nullptr)
178018f8f608SEd Tanous         {
178118f8f608SEd Tanous             continue;
178218f8f608SEd Tanous         }
178318f8f608SEd Tanous         if (nameS == *name)
1784adc4f0dbSShawn McCarney         {
1785adc4f0dbSShawn McCarney             return powerSupply;
1786adc4f0dbSShawn McCarney         }
1787adc4f0dbSShawn McCarney     }
1788adc4f0dbSShawn McCarney 
1789adc4f0dbSShawn McCarney     // Add new PowerSupply object to JSON array
1790adc4f0dbSShawn McCarney     powerSupplyArray.push_back({});
1791adc4f0dbSShawn McCarney     nlohmann::json& powerSupply = powerSupplyArray.back();
1792bd79bce8SPatrick Williams     boost::urls::url url =
1793bd79bce8SPatrick Williams         boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
1794eddfc437SWilly Tu     url.set_fragment(("/PowerSupplies"_json_pointer).to_string());
1795eddfc437SWilly Tu     powerSupply["@odata.id"] = std::move(url);
179618f8f608SEd Tanous     std::string escaped;
17976f4bd290SAlexander Hansen     escaped.resize(inventoryItem.name.size());
179818f8f608SEd Tanous     std::ranges::replace_copy(inventoryItem.name, escaped.begin(), '_', ' ');
179918f8f608SEd Tanous     powerSupply["Name"] = std::move(escaped);
1800adc4f0dbSShawn McCarney     powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1801adc4f0dbSShawn McCarney     powerSupply["Model"] = inventoryItem.model;
1802adc4f0dbSShawn McCarney     powerSupply["PartNumber"] = inventoryItem.partNumber;
1803adc4f0dbSShawn McCarney     powerSupply["SerialNumber"] = inventoryItem.serialNumber;
1804c9563608SJanet Adkins     sensor_utils::setLedState(powerSupply, &inventoryItem);
1805adc4f0dbSShawn McCarney 
180642cbe538SGunnar Mills     if (inventoryItem.powerSupplyEfficiencyPercent >= 0)
180742cbe538SGunnar Mills     {
180842cbe538SGunnar Mills         powerSupply["EfficiencyPercent"] =
180942cbe538SGunnar Mills             inventoryItem.powerSupplyEfficiencyPercent;
181042cbe538SGunnar Mills     }
181142cbe538SGunnar Mills 
1812c9563608SJanet Adkins     powerSupply["Status"]["State"] =
1813c9563608SJanet Adkins         sensor_utils::getState(&inventoryItem, true);
1814adc4f0dbSShawn McCarney     const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1815adc4f0dbSShawn McCarney     powerSupply["Status"]["Health"] = health;
1816adc4f0dbSShawn McCarney 
1817adc4f0dbSShawn McCarney     return powerSupply;
18188fb49dd6SShawn McCarney }
18198fb49dd6SShawn McCarney 
18208fb49dd6SShawn McCarney /**
1821de629b6eSShawn McCarney  * @brief Gets the values of the specified sensors.
1822de629b6eSShawn McCarney  *
1823de629b6eSShawn McCarney  * Stores the results as JSON in the SensorsAsyncResp.
1824de629b6eSShawn McCarney  *
1825de629b6eSShawn McCarney  * Gets the sensor values asynchronously.  Stores the results later when the
1826de629b6eSShawn McCarney  * information has been obtained.
1827de629b6eSShawn McCarney  *
1828adc4f0dbSShawn McCarney  * The sensorNames set contains all requested sensors for the current chassis.
1829de629b6eSShawn McCarney  *
1830de629b6eSShawn McCarney  * To minimize the number of DBus calls, the DBus method
1831de629b6eSShawn McCarney  * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1832de629b6eSShawn McCarney  * values of all sensors provided by a connection (service).
1833de629b6eSShawn McCarney  *
1834de629b6eSShawn McCarney  * The connections set contains all the connections that provide sensor values.
1835de629b6eSShawn McCarney  *
1836adc4f0dbSShawn McCarney  * The InventoryItem vector contains D-Bus inventory items associated with the
1837adc4f0dbSShawn McCarney  * sensors.  Inventory item data is needed for some Redfish sensor properties.
1838adc4f0dbSShawn McCarney  *
1839de629b6eSShawn McCarney  * @param SensorsAsyncResp Pointer to object holding response data.
1840adc4f0dbSShawn McCarney  * @param sensorNames All requested sensors within the current chassis.
1841de629b6eSShawn McCarney  * @param connections Connections that provide sensor values.
1842de629b6eSShawn McCarney  * implements ObjectManager.
1843adc4f0dbSShawn McCarney  * @param inventoryItems Inventory items associated with the sensors.
1844de629b6eSShawn McCarney  */
184523a21a1cSEd Tanous inline void getSensorData(
184681ce609eSEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1847fe04d49cSNan Zhou     const std::shared_ptr<std::set<std::string>>& sensorNames,
1848fe04d49cSNan Zhou     const std::set<std::string>& connections,
1849b5a76932SEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems)
1850de629b6eSShawn McCarney {
185162598e31SEd Tanous     BMCWEB_LOG_DEBUG("getSensorData enter");
1852de629b6eSShawn McCarney     // Get managed objects from all services exposing sensors
1853de629b6eSShawn McCarney     for (const std::string& connection : connections)
1854de629b6eSShawn McCarney     {
18555eb468daSGeorge Liu         sdbusplus::message::object_path sensorPath(
18565eb468daSGeorge Liu             "/xyz/openbmc_project/sensors");
18575eb468daSGeorge Liu         dbus::utility::getManagedObjects(
18585eb468daSGeorge Liu             connection, sensorPath,
1859002d39b4SEd Tanous             [sensorsAsyncResp, sensorNames,
18605e7e2dc5SEd Tanous              inventoryItems](const boost::system::error_code& ec,
186102cad96eSEd Tanous                              const dbus::utility::ManagedObjectType& resp) {
186262598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getManagedObjectsCb enter");
1863de629b6eSShawn McCarney                 if (ec)
1864de629b6eSShawn McCarney                 {
186562598e31SEd Tanous                     BMCWEB_LOG_ERROR("getManagedObjectsCb DBUS error: {}", ec);
18668d1b46d7Szhanghch05                     messages::internalError(sensorsAsyncResp->asyncResp->res);
1867de629b6eSShawn McCarney                     return;
1868de629b6eSShawn McCarney                 }
18690c728b42SJanet Adkins                 auto chassisSubNode = sensor_utils::chassisSubNodeFromString(
18700c728b42SJanet Adkins                     sensorsAsyncResp->chassisSubNode);
1871de629b6eSShawn McCarney                 // Go through all objects and update response with sensor data
1872de629b6eSShawn McCarney                 for (const auto& objDictEntry : resp)
1873de629b6eSShawn McCarney                 {
1874de629b6eSShawn McCarney                     const std::string& objPath =
1875de629b6eSShawn McCarney                         static_cast<const std::string&>(objDictEntry.first);
187662598e31SEd Tanous                     BMCWEB_LOG_DEBUG("getManagedObjectsCb parsing object {}",
187762598e31SEd Tanous                                      objPath);
1878de629b6eSShawn McCarney 
1879de629b6eSShawn McCarney                     std::vector<std::string> split;
1880de629b6eSShawn McCarney                     // Reserve space for
1881de629b6eSShawn McCarney                     // /xyz/openbmc_project/sensors/<name>/<subname>
1882de629b6eSShawn McCarney                     split.reserve(6);
188350ebd4afSEd Tanous                     // NOLINTNEXTLINE
188450ebd4afSEd Tanous                     bmcweb::split(split, objPath, '/');
1885de629b6eSShawn McCarney                     if (split.size() < 6)
1886de629b6eSShawn McCarney                     {
188762598e31SEd Tanous                         BMCWEB_LOG_ERROR("Got path that isn't long enough {}",
188862598e31SEd Tanous                                          objPath);
1889de629b6eSShawn McCarney                         continue;
1890de629b6eSShawn McCarney                     }
189150ebd4afSEd Tanous                     // These indexes aren't intuitive, as split puts an empty
1892de629b6eSShawn McCarney                     // string at the beginning
1893de629b6eSShawn McCarney                     const std::string& sensorType = split[4];
1894de629b6eSShawn McCarney                     const std::string& sensorName = split[5];
189562598e31SEd Tanous                     BMCWEB_LOG_DEBUG("sensorName {} sensorType {}", sensorName,
189662598e31SEd Tanous                                      sensorType);
189749c53ac9SJohnathan Mantey                     if (sensorNames->find(objPath) == sensorNames->end())
1898de629b6eSShawn McCarney                     {
189962598e31SEd Tanous                         BMCWEB_LOG_DEBUG("{} not in sensor list ", sensorName);
1900de629b6eSShawn McCarney                         continue;
1901de629b6eSShawn McCarney                     }
1902de629b6eSShawn McCarney 
1903adc4f0dbSShawn McCarney                     // Find inventory item (if any) associated with sensor
1904adc4f0dbSShawn McCarney                     InventoryItem* inventoryItem =
1905adc4f0dbSShawn McCarney                         findInventoryItemForSensor(inventoryItems, objPath);
1906adc4f0dbSShawn McCarney 
190795a3ecadSAnthony Wilson                     const std::string& sensorSchema =
190881ce609eSEd Tanous                         sensorsAsyncResp->chassisSubNode;
190995a3ecadSAnthony Wilson 
191095a3ecadSAnthony Wilson                     nlohmann::json* sensorJson = nullptr;
191195a3ecadSAnthony Wilson 
19120c728b42SJanet Adkins                     if (sensorSchema == sensors::sensorsNodeStr &&
1913928fefb9SNan Zhou                         !sensorsAsyncResp->efficientExpand)
191495a3ecadSAnthony Wilson                     {
19151516c21bSJanet Adkins                         std::string sensorId =
19161516c21bSJanet Adkins                             redfish::sensor_utils::getSensorId(sensorName,
19171516c21bSJanet Adkins                                                                sensorType);
1918c1d019a6SEd Tanous 
1919bd79bce8SPatrick Williams                         sensorsAsyncResp->asyncResp->res
1920bd79bce8SPatrick Williams                             .jsonValue["@odata.id"] = boost::urls::format(
1921bd79bce8SPatrick Williams                             "/redfish/v1/Chassis/{}/{}/{}",
1922c1d019a6SEd Tanous                             sensorsAsyncResp->chassisId,
1923bd79bce8SPatrick Williams                             sensorsAsyncResp->chassisSubNode, sensorId);
1924bd79bce8SPatrick Williams                         sensorJson =
1925bd79bce8SPatrick Williams                             &(sensorsAsyncResp->asyncResp->res.jsonValue);
192695a3ecadSAnthony Wilson                     }
192795a3ecadSAnthony Wilson                     else
192895a3ecadSAnthony Wilson                     {
1929271584abSEd Tanous                         std::string fieldName;
1930928fefb9SNan Zhou                         if (sensorsAsyncResp->efficientExpand)
1931928fefb9SNan Zhou                         {
1932928fefb9SNan Zhou                             fieldName = "Members";
1933928fefb9SNan Zhou                         }
1934928fefb9SNan Zhou                         else if (sensorType == "temperature")
1935de629b6eSShawn McCarney                         {
1936de629b6eSShawn McCarney                             fieldName = "Temperatures";
1937de629b6eSShawn McCarney                         }
1938bd79bce8SPatrick Williams                         else if (sensorType == "fan" ||
1939bd79bce8SPatrick Williams                                  sensorType == "fan_tach" ||
1940de629b6eSShawn McCarney                                  sensorType == "fan_pwm")
1941de629b6eSShawn McCarney                         {
1942de629b6eSShawn McCarney                             fieldName = "Fans";
1943de629b6eSShawn McCarney                         }
1944de629b6eSShawn McCarney                         else if (sensorType == "voltage")
1945de629b6eSShawn McCarney                         {
1946de629b6eSShawn McCarney                             fieldName = "Voltages";
1947de629b6eSShawn McCarney                         }
1948de629b6eSShawn McCarney                         else if (sensorType == "power")
1949de629b6eSShawn McCarney                         {
195055f79e6fSEd Tanous                             if (sensorName == "total_power")
1951028f7ebcSEddie James                             {
1952028f7ebcSEddie James                                 fieldName = "PowerControl";
1953028f7ebcSEddie James                             }
1954adc4f0dbSShawn McCarney                             else if ((inventoryItem != nullptr) &&
1955adc4f0dbSShawn McCarney                                      (inventoryItem->isPowerSupply))
1956028f7ebcSEddie James                             {
1957de629b6eSShawn McCarney                                 fieldName = "PowerSupplies";
1958de629b6eSShawn McCarney                             }
1959adc4f0dbSShawn McCarney                             else
1960adc4f0dbSShawn McCarney                             {
1961adc4f0dbSShawn McCarney                                 // Other power sensors are in SensorCollection
1962adc4f0dbSShawn McCarney                                 continue;
1963adc4f0dbSShawn McCarney                             }
1964028f7ebcSEddie James                         }
1965de629b6eSShawn McCarney                         else
1966de629b6eSShawn McCarney                         {
1967bd79bce8SPatrick Williams                             BMCWEB_LOG_ERROR(
1968bd79bce8SPatrick Williams                                 "Unsure how to handle sensorType {}",
196962598e31SEd Tanous                                 sensorType);
1970de629b6eSShawn McCarney                             continue;
1971de629b6eSShawn McCarney                         }
1972de629b6eSShawn McCarney 
1973de629b6eSShawn McCarney                         nlohmann::json& tempArray =
1974bd79bce8SPatrick Williams                             sensorsAsyncResp->asyncResp->res
1975bd79bce8SPatrick Williams                                 .jsonValue[fieldName];
1976adc4f0dbSShawn McCarney                         if (fieldName == "PowerControl")
197749c53ac9SJohnathan Mantey                         {
1978adc4f0dbSShawn McCarney                             if (tempArray.empty())
19797ab06f49SGunnar Mills                             {
198095a3ecadSAnthony Wilson                                 // Put multiple "sensors" into a single
198195a3ecadSAnthony Wilson                                 // PowerControl. Follows MemberId naming and
198295a3ecadSAnthony Wilson                                 // naming in power.hpp.
19831476687dSEd Tanous                                 nlohmann::json::object_t power;
1984ef4c65b7SEd Tanous                                 boost::urls::url url = boost::urls::format(
1985ef4c65b7SEd Tanous                                     "/redfish/v1/Chassis/{}/{}",
1986eddfc437SWilly Tu                                     sensorsAsyncResp->chassisId,
1987eddfc437SWilly Tu                                     sensorsAsyncResp->chassisSubNode);
1988bd79bce8SPatrick Williams                                 url.set_fragment(
1989bd79bce8SPatrick Williams                                     (""_json_pointer / fieldName / "0")
1990eddfc437SWilly Tu                                         .to_string());
1991eddfc437SWilly Tu                                 power["@odata.id"] = std::move(url);
1992b2ba3072SPatrick Williams                                 tempArray.emplace_back(std::move(power));
1993adc4f0dbSShawn McCarney                             }
1994adc4f0dbSShawn McCarney                             sensorJson = &(tempArray.back());
1995adc4f0dbSShawn McCarney                         }
1996adc4f0dbSShawn McCarney                         else if (fieldName == "PowerSupplies")
1997adc4f0dbSShawn McCarney                         {
1998adc4f0dbSShawn McCarney                             if (inventoryItem != nullptr)
1999adc4f0dbSShawn McCarney                             {
2000bd79bce8SPatrick Williams                                 sensorJson = &(getPowerSupply(
2001bd79bce8SPatrick Williams                                     tempArray, *inventoryItem,
200281ce609eSEd Tanous                                     sensorsAsyncResp->chassisId));
2003adc4f0dbSShawn McCarney                             }
200449c53ac9SJohnathan Mantey                         }
2005928fefb9SNan Zhou                         else if (fieldName == "Members")
2006928fefb9SNan Zhou                         {
20071516c21bSJanet Adkins                             std::string sensorId =
20081516c21bSJanet Adkins                                 redfish::sensor_utils::getSensorId(sensorName,
20091516c21bSJanet Adkins                                                                    sensorType);
2010677bb756SEd Tanous 
20111476687dSEd Tanous                             nlohmann::json::object_t member;
2012ef4c65b7SEd Tanous                             member["@odata.id"] = boost::urls::format(
2013ef4c65b7SEd Tanous                                 "/redfish/v1/Chassis/{}/{}/{}",
2014677bb756SEd Tanous                                 sensorsAsyncResp->chassisId,
2015677bb756SEd Tanous                                 sensorsAsyncResp->chassisSubNode, sensorId);
2016b2ba3072SPatrick Williams                             tempArray.emplace_back(std::move(member));
2017928fefb9SNan Zhou                             sensorJson = &(tempArray.back());
2018928fefb9SNan Zhou                         }
201949c53ac9SJohnathan Mantey                         else
202049c53ac9SJohnathan Mantey                         {
20211476687dSEd Tanous                             nlohmann::json::object_t member;
2022ef4c65b7SEd Tanous                             boost::urls::url url = boost::urls::format(
2023ef4c65b7SEd Tanous                                 "/redfish/v1/Chassis/{}/{}",
2024eddfc437SWilly Tu                                 sensorsAsyncResp->chassisId,
2025eddfc437SWilly Tu                                 sensorsAsyncResp->chassisSubNode);
2026eddfc437SWilly Tu                             url.set_fragment(
2027eddfc437SWilly Tu                                 (""_json_pointer / fieldName).to_string());
2028eddfc437SWilly Tu                             member["@odata.id"] = std::move(url);
2029b2ba3072SPatrick Williams                             tempArray.emplace_back(std::move(member));
2030adc4f0dbSShawn McCarney                             sensorJson = &(tempArray.back());
203149c53ac9SJohnathan Mantey                         }
203295a3ecadSAnthony Wilson                     }
2033de629b6eSShawn McCarney 
2034adc4f0dbSShawn McCarney                     if (sensorJson != nullptr)
2035adc4f0dbSShawn McCarney                     {
20360c728b42SJanet Adkins                         objectInterfacesToJson(
20370c728b42SJanet Adkins                             sensorName, sensorType, chassisSubNode,
20380c728b42SJanet Adkins                             objDictEntry.second, *sensorJson, inventoryItem);
20391d7c0054SEd Tanous 
20401d7c0054SEd Tanous                         std::string path = "/xyz/openbmc_project/sensors/";
20411d7c0054SEd Tanous                         path += sensorType;
20421d7c0054SEd Tanous                         path += "/";
20431d7c0054SEd Tanous                         path += sensorName;
2044c1d019a6SEd Tanous                         sensorsAsyncResp->addMetadata(*sensorJson, path);
2045adc4f0dbSShawn McCarney                     }
2046de629b6eSShawn McCarney                 }
204781ce609eSEd Tanous                 if (sensorsAsyncResp.use_count() == 1)
204849c53ac9SJohnathan Mantey                 {
204981ce609eSEd Tanous                     sortJSONResponse(sensorsAsyncResp);
20500c728b42SJanet Adkins                     if (chassisSubNode ==
20510c728b42SJanet Adkins                             sensor_utils::ChassisSubNode::sensorsNode &&
2052928fefb9SNan Zhou                         sensorsAsyncResp->efficientExpand)
2053928fefb9SNan Zhou                     {
2054928fefb9SNan Zhou                         sensorsAsyncResp->asyncResp->res
2055928fefb9SNan Zhou                             .jsonValue["Members@odata.count"] =
2056bd79bce8SPatrick Williams                             sensorsAsyncResp->asyncResp->res
2057bd79bce8SPatrick Williams                                 .jsonValue["Members"]
2058928fefb9SNan Zhou                                 .size();
2059928fefb9SNan Zhou                     }
20600c728b42SJanet Adkins                     else if (chassisSubNode ==
20610c728b42SJanet Adkins                              sensor_utils::ChassisSubNode::thermalNode)
20628bd25ccdSJames Feist                     {
206381ce609eSEd Tanous                         populateFanRedundancy(sensorsAsyncResp);
20648bd25ccdSJames Feist                     }
206549c53ac9SJohnathan Mantey                 }
206662598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getManagedObjectsCb exit");
20675eb468daSGeorge Liu             });
206823a21a1cSEd Tanous     }
206962598e31SEd Tanous     BMCWEB_LOG_DEBUG("getSensorData exit");
2070de629b6eSShawn McCarney }
2071de629b6eSShawn McCarney 
2072*504af5a0SPatrick Williams inline void processSensorList(
2073*504af5a0SPatrick Williams     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
2074fe04d49cSNan Zhou     const std::shared_ptr<std::set<std::string>>& sensorNames)
20751abe55efSEd Tanous {
2076fe04d49cSNan Zhou     auto getConnectionCb = [sensorsAsyncResp, sensorNames](
2077fe04d49cSNan Zhou                                const std::set<std::string>& connections) {
207862598e31SEd Tanous         BMCWEB_LOG_DEBUG("getConnectionCb enter");
2079adc4f0dbSShawn McCarney         auto getInventoryItemsCb =
2080bd79bce8SPatrick Williams             [sensorsAsyncResp, sensorNames, connections](
2081bd79bce8SPatrick Williams                 const std::shared_ptr<std::vector<InventoryItem>>&
20824e0d8789SEd Tanous                     inventoryItems) mutable {
208362598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryItemsCb enter");
208449c53ac9SJohnathan Mantey                 // Get sensor data and store results in JSON
2085002d39b4SEd Tanous                 getSensorData(sensorsAsyncResp, sensorNames, connections,
2086d0090733SEd Tanous                               inventoryItems);
208762598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryItemsCb exit");
2088adc4f0dbSShawn McCarney             };
2089adc4f0dbSShawn McCarney 
2090adc4f0dbSShawn McCarney         // Get inventory items associated with sensors
2091d0090733SEd Tanous         getInventoryItems(sensorsAsyncResp, sensorNames,
2092adc4f0dbSShawn McCarney                           std::move(getInventoryItemsCb));
2093adc4f0dbSShawn McCarney 
209462598e31SEd Tanous         BMCWEB_LOG_DEBUG("getConnectionCb exit");
209508777fb0SLewanczyk, Dawid     };
2096de629b6eSShawn McCarney 
2097de629b6eSShawn McCarney     // Get set of connections that provide sensor values
209881ce609eSEd Tanous     getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb));
209995a3ecadSAnthony Wilson }
210095a3ecadSAnthony Wilson 
210195a3ecadSAnthony Wilson /**
210295a3ecadSAnthony Wilson  * @brief Entry point for retrieving sensors data related to requested
210395a3ecadSAnthony Wilson  *        chassis.
210495a3ecadSAnthony Wilson  * @param SensorsAsyncResp   Pointer to object holding response data
210595a3ecadSAnthony Wilson  */
2106*504af5a0SPatrick Williams inline void getChassisData(
2107*504af5a0SPatrick Williams     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
210895a3ecadSAnthony Wilson {
210962598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassisData enter");
211095a3ecadSAnthony Wilson     auto getChassisCb =
211181ce609eSEd Tanous         [sensorsAsyncResp](
2112fe04d49cSNan Zhou             const std::shared_ptr<std::set<std::string>>& sensorNames) {
211362598e31SEd Tanous             BMCWEB_LOG_DEBUG("getChassisCb enter");
211481ce609eSEd Tanous             processSensorList(sensorsAsyncResp, sensorNames);
211562598e31SEd Tanous             BMCWEB_LOG_DEBUG("getChassisCb exit");
211608777fb0SLewanczyk, Dawid         };
2117928fefb9SNan Zhou     // SensorCollection doesn't contain the Redundancy property
21180c728b42SJanet Adkins     if (sensorsAsyncResp->chassisSubNode != sensors::sensorsNodeStr)
2119928fefb9SNan Zhou     {
21208d1b46d7Szhanghch05         sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
21218d1b46d7Szhanghch05             nlohmann::json::array();
2122928fefb9SNan Zhou     }
212326f03899SShawn McCarney     // Get set of sensors in chassis
21247f1cc26dSEd Tanous     getChassis(sensorsAsyncResp->asyncResp, sensorsAsyncResp->chassisId,
21257f1cc26dSEd Tanous                sensorsAsyncResp->chassisSubNode, sensorsAsyncResp->types,
21267f1cc26dSEd Tanous                std::move(getChassisCb));
212762598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassisData exit");
2128271584abSEd Tanous }
212908777fb0SLewanczyk, Dawid 
2130413961deSRichard Marian Thomaiyar /**
213149c53ac9SJohnathan Mantey  * @brief Find the requested sensorName in the list of all sensors supplied by
213249c53ac9SJohnathan Mantey  * the chassis node
213349c53ac9SJohnathan Mantey  *
213449c53ac9SJohnathan Mantey  * @param sensorName   The sensor name supplied in the PATCH request
213549c53ac9SJohnathan Mantey  * @param sensorsList  The list of sensors managed by the chassis node
213649c53ac9SJohnathan Mantey  * @param sensorsModified  The list of sensors that were found as a result of
213749c53ac9SJohnathan Mantey  *                         repeated calls to this function
213849c53ac9SJohnathan Mantey  */
2139bd79bce8SPatrick Williams inline bool findSensorNameUsingSensorPath(
2140bd79bce8SPatrick Williams     std::string_view sensorName, const std::set<std::string>& sensorsList,
2141fe04d49cSNan Zhou     std::set<std::string>& sensorsModified)
214249c53ac9SJohnathan Mantey {
2143fe04d49cSNan Zhou     for (const auto& chassisSensor : sensorsList)
214449c53ac9SJohnathan Mantey     {
214528aa8de5SGeorge Liu         sdbusplus::message::object_path path(chassisSensor);
2146b00dcc27SEd Tanous         std::string thisSensorName = path.filename();
214728aa8de5SGeorge Liu         if (thisSensorName.empty())
214849c53ac9SJohnathan Mantey         {
214949c53ac9SJohnathan Mantey             continue;
215049c53ac9SJohnathan Mantey         }
215149c53ac9SJohnathan Mantey         if (thisSensorName == sensorName)
215249c53ac9SJohnathan Mantey         {
215349c53ac9SJohnathan Mantey             sensorsModified.emplace(chassisSensor);
215449c53ac9SJohnathan Mantey             return true;
215549c53ac9SJohnathan Mantey         }
215649c53ac9SJohnathan Mantey     }
215749c53ac9SJohnathan Mantey     return false;
215849c53ac9SJohnathan Mantey }
215949c53ac9SJohnathan Mantey 
216049c53ac9SJohnathan Mantey /**
2161413961deSRichard Marian Thomaiyar  * @brief Entry point for overriding sensor values of given sensor
2162413961deSRichard Marian Thomaiyar  *
21638d1b46d7Szhanghch05  * @param sensorAsyncResp   response object
21644bb3dc34SCarol Wang  * @param allCollections   Collections extract from sensors' request patch info
2165413961deSRichard Marian Thomaiyar  * @param chassisSubNode   Chassis Node for which the query has to happen
2166413961deSRichard Marian Thomaiyar  */
216723a21a1cSEd Tanous inline void setSensorsOverride(
2168b5a76932SEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
21690885057cSEd Tanous     std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>&
2170397fd61fSjayaprakash Mutyala         allCollections)
2171413961deSRichard Marian Thomaiyar {
217262598e31SEd Tanous     BMCWEB_LOG_INFO("setSensorsOverride for subNode{}",
217362598e31SEd Tanous                     sensorAsyncResp->chassisSubNode);
2174413961deSRichard Marian Thomaiyar 
2175d02aad39SEd Tanous     std::string_view propertyValueName;
2176f65af9e8SRichard Marian Thomaiyar     std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
2177413961deSRichard Marian Thomaiyar     std::string memberId;
2178543f4400SEd Tanous     double value = 0.0;
2179f65af9e8SRichard Marian Thomaiyar     for (auto& collectionItems : allCollections)
2180f65af9e8SRichard Marian Thomaiyar     {
2181f65af9e8SRichard Marian Thomaiyar         if (collectionItems.first == "Temperatures")
2182f65af9e8SRichard Marian Thomaiyar         {
2183f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingCelsius";
2184f65af9e8SRichard Marian Thomaiyar         }
2185f65af9e8SRichard Marian Thomaiyar         else if (collectionItems.first == "Fans")
2186f65af9e8SRichard Marian Thomaiyar         {
2187f65af9e8SRichard Marian Thomaiyar             propertyValueName = "Reading";
2188f65af9e8SRichard Marian Thomaiyar         }
2189f65af9e8SRichard Marian Thomaiyar         else
2190f65af9e8SRichard Marian Thomaiyar         {
2191f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingVolts";
2192f65af9e8SRichard Marian Thomaiyar         }
2193f65af9e8SRichard Marian Thomaiyar         for (auto& item : collectionItems.second)
2194f65af9e8SRichard Marian Thomaiyar         {
2195afc474aeSMyung Bae             if (!json_util::readJsonObject(                //
2196afc474aeSMyung Bae                     item, sensorAsyncResp->asyncResp->res, //
2197afc474aeSMyung Bae                     "MemberId", memberId,                  //
2198afc474aeSMyung Bae                     propertyValueName, value               //
2199afc474aeSMyung Bae                     ))
2200413961deSRichard Marian Thomaiyar             {
2201413961deSRichard Marian Thomaiyar                 return;
2202413961deSRichard Marian Thomaiyar             }
2203f65af9e8SRichard Marian Thomaiyar             overrideMap.emplace(memberId,
2204f65af9e8SRichard Marian Thomaiyar                                 std::make_pair(value, collectionItems.first));
2205f65af9e8SRichard Marian Thomaiyar         }
2206f65af9e8SRichard Marian Thomaiyar     }
22074bb3dc34SCarol Wang 
2208bd79bce8SPatrick Williams     auto getChassisSensorListCb = [sensorAsyncResp, overrideMap,
2209bd79bce8SPatrick Williams                                    propertyValueNameStr =
2210bd79bce8SPatrick Williams                                        std::string(propertyValueName)](
2211bd79bce8SPatrick Williams                                       const std::shared_ptr<
2212bd79bce8SPatrick Williams                                           std::set<std::string>>& sensorsList) {
221349c53ac9SJohnathan Mantey         // Match sensor names in the PATCH request to those managed by the
221449c53ac9SJohnathan Mantey         // chassis node
2215fe04d49cSNan Zhou         const std::shared_ptr<std::set<std::string>> sensorNames =
2216fe04d49cSNan Zhou             std::make_shared<std::set<std::string>>();
2217f65af9e8SRichard Marian Thomaiyar         for (const auto& item : overrideMap)
2218413961deSRichard Marian Thomaiyar         {
2219f65af9e8SRichard Marian Thomaiyar             const auto& sensor = item.first;
2220c71d6125SEd Tanous             std::pair<std::string, std::string> sensorNameType =
22211516c21bSJanet Adkins                 redfish::sensor_utils::splitSensorNameAndType(sensor);
2222c71d6125SEd Tanous             if (!findSensorNameUsingSensorPath(sensorNameType.second,
2223c71d6125SEd Tanous                                                *sensorsList, *sensorNames))
2224f65af9e8SRichard Marian Thomaiyar             {
222562598e31SEd Tanous                 BMCWEB_LOG_INFO("Unable to find memberId {}", item.first);
22268d1b46d7Szhanghch05                 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
2227f65af9e8SRichard Marian Thomaiyar                                            item.second.second, item.first);
2228413961deSRichard Marian Thomaiyar                 return;
2229413961deSRichard Marian Thomaiyar             }
2230f65af9e8SRichard Marian Thomaiyar         }
2231413961deSRichard Marian Thomaiyar         // Get the connection to which the memberId belongs
2232bd79bce8SPatrick Williams         auto getObjectsWithConnectionCb = [sensorAsyncResp, overrideMap,
2233bd79bce8SPatrick Williams                                            propertyValueNameStr](
2234bd79bce8SPatrick Williams                                               const std::set<
2235bd79bce8SPatrick Williams                                                   std::string>& /*connections*/,
2236bd79bce8SPatrick Williams                                               const std::set<std::pair<
2237bd79bce8SPatrick Williams                                                   std::string, std::string>>&
2238413961deSRichard Marian Thomaiyar                                                   objectsWithConnection) {
2239f65af9e8SRichard Marian Thomaiyar             if (objectsWithConnection.size() != overrideMap.size())
2240413961deSRichard Marian Thomaiyar             {
224162598e31SEd Tanous                 BMCWEB_LOG_INFO(
224262598e31SEd Tanous                     "Unable to find all objects with proper connection {} requested {}",
224362598e31SEd Tanous                     objectsWithConnection.size(), overrideMap.size());
2244bd79bce8SPatrick Williams                 messages::resourceNotFound(
2245bd79bce8SPatrick Williams                     sensorAsyncResp->asyncResp->res,
22460c728b42SJanet Adkins                     sensorAsyncResp->chassisSubNode == sensors::thermalNodeStr
2247413961deSRichard Marian Thomaiyar                         ? "Temperatures"
2248413961deSRichard Marian Thomaiyar                         : "Voltages",
2249f65af9e8SRichard Marian Thomaiyar                     "Count");
2250f65af9e8SRichard Marian Thomaiyar                 return;
2251f65af9e8SRichard Marian Thomaiyar             }
2252f65af9e8SRichard Marian Thomaiyar             for (const auto& item : objectsWithConnection)
2253f65af9e8SRichard Marian Thomaiyar             {
225428aa8de5SGeorge Liu                 sdbusplus::message::object_path path(item.first);
225528aa8de5SGeorge Liu                 std::string sensorName = path.filename();
225628aa8de5SGeorge Liu                 if (sensorName.empty())
2257f65af9e8SRichard Marian Thomaiyar                 {
22584f277b54SJayaprakash Mutyala                     messages::internalError(sensorAsyncResp->asyncResp->res);
2259f65af9e8SRichard Marian Thomaiyar                     return;
2260f65af9e8SRichard Marian Thomaiyar                 }
22611516c21bSJanet Adkins                 std::string id = redfish::sensor_utils::getSensorId(
22621516c21bSJanet Adkins                     sensorName, path.parent_path().filename());
2263f65af9e8SRichard Marian Thomaiyar 
22643f5eb755SBan Feng                 const auto& iterator = overrideMap.find(id);
2265f65af9e8SRichard Marian Thomaiyar                 if (iterator == overrideMap.end())
2266f65af9e8SRichard Marian Thomaiyar                 {
226762598e31SEd Tanous                     BMCWEB_LOG_INFO("Unable to find sensor object{}",
226862598e31SEd Tanous                                     item.first);
22694f277b54SJayaprakash Mutyala                     messages::internalError(sensorAsyncResp->asyncResp->res);
2270413961deSRichard Marian Thomaiyar                     return;
2271413961deSRichard Marian Thomaiyar                 }
2272e93abac6SGinu George                 setDbusProperty(sensorAsyncResp->asyncResp,
2273e93abac6SGinu George                                 propertyValueNameStr, item.second, item.first,
2274e93abac6SGinu George                                 "xyz.openbmc_project.Sensor.Value", "Value",
2275d02aad39SEd Tanous                                 iterator->second.first);
2276f65af9e8SRichard Marian Thomaiyar             }
2277413961deSRichard Marian Thomaiyar         };
2278413961deSRichard Marian Thomaiyar         // Get object with connection for the given sensor name
2279413961deSRichard Marian Thomaiyar         getObjectsWithConnection(sensorAsyncResp, sensorNames,
2280413961deSRichard Marian Thomaiyar                                  std::move(getObjectsWithConnectionCb));
2281413961deSRichard Marian Thomaiyar     };
2282413961deSRichard Marian Thomaiyar     // get full sensor list for the given chassisId and cross verify the sensor.
22837f1cc26dSEd Tanous     getChassis(sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId,
22847f1cc26dSEd Tanous                sensorAsyncResp->chassisSubNode, sensorAsyncResp->types,
22857f1cc26dSEd Tanous                std::move(getChassisSensorListCb));
2286413961deSRichard Marian Thomaiyar }
2287413961deSRichard Marian Thomaiyar 
2288a0ec28b6SAdrian Ambrożewicz /**
2289a0ec28b6SAdrian Ambrożewicz  * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus
2290a0ec28b6SAdrian Ambrożewicz  * path of the sensor.
2291a0ec28b6SAdrian Ambrożewicz  *
2292a0ec28b6SAdrian Ambrożewicz  * Function builds valid Redfish response for sensor query of given chassis and
2293a0ec28b6SAdrian Ambrożewicz  * node. It then builds metadata about Redfish<->D-Bus correlations and provides
2294a0ec28b6SAdrian Ambrożewicz  * it to caller in a callback.
2295a0ec28b6SAdrian Ambrożewicz  *
2296a0ec28b6SAdrian Ambrożewicz  * @param chassis   Chassis for which retrieval should be performed
2297c9563608SJanet Adkins  * @param node  Node (group) of sensors. See sensor_utils::node for supported
2298c9563608SJanet Adkins  * values
2299a0ec28b6SAdrian Ambrożewicz  * @param mapComplete   Callback to be called with retrieval result
2300a0ec28b6SAdrian Ambrożewicz  */
2301931edc79SEd Tanous template <typename Callback>
2302bd79bce8SPatrick Williams inline void retrieveUriToDbusMap(
2303bd79bce8SPatrick Williams     const std::string& chassis, const std::string& node, Callback&& mapComplete)
2304a0ec28b6SAdrian Ambrożewicz {
230502da7c5aSEd Tanous     decltype(sensors::paths)::const_iterator pathIt =
230602da7c5aSEd Tanous         std::find_if(sensors::paths.cbegin(), sensors::paths.cend(),
230702da7c5aSEd Tanous                      [&node](auto&& val) { return val.first == node; });
230802da7c5aSEd Tanous     if (pathIt == sensors::paths.cend())
2309a0ec28b6SAdrian Ambrożewicz     {
231062598e31SEd Tanous         BMCWEB_LOG_ERROR("Wrong node provided : {}", node);
23116804b5c8SEd Tanous         std::map<std::string, std::string> noop;
23126804b5c8SEd Tanous         mapComplete(boost::beast::http::status::bad_request, noop);
2313a0ec28b6SAdrian Ambrożewicz         return;
2314a0ec28b6SAdrian Ambrożewicz     }
2315d51e072fSKrzysztof Grobelny 
231672374eb7SNan Zhou     auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
2317bd79bce8SPatrick Williams     auto callback =
2318bd79bce8SPatrick Williams         [asyncResp, mapCompleteCb = std::forward<Callback>(mapComplete)](
2319a0ec28b6SAdrian Ambrożewicz             const boost::beast::http::status status,
2320fe04d49cSNan Zhou             const std::map<std::string, std::string>& uriToDbus) {
2321fe04d49cSNan Zhou             mapCompleteCb(status, uriToDbus);
2322fe04d49cSNan Zhou         };
2323a0ec28b6SAdrian Ambrożewicz 
2324a0ec28b6SAdrian Ambrożewicz     auto resp = std::make_shared<SensorsAsyncResp>(
2325d51e072fSKrzysztof Grobelny         asyncResp, chassis, pathIt->second, node, std::move(callback));
2326a0ec28b6SAdrian Ambrożewicz     getChassisData(resp);
2327a0ec28b6SAdrian Ambrożewicz }
2328a0ec28b6SAdrian Ambrożewicz 
2329bacb2162SNan Zhou namespace sensors
2330bacb2162SNan Zhou {
2331928fefb9SNan Zhou 
2332bacb2162SNan Zhou inline void getChassisCallback(
2333c1d019a6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2334c1d019a6SEd Tanous     std::string_view chassisId, std::string_view chassisSubNode,
2335fe04d49cSNan Zhou     const std::shared_ptr<std::set<std::string>>& sensorNames)
2336bacb2162SNan Zhou {
233762598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassisCallback enter ");
2338bacb2162SNan Zhou 
2339c1d019a6SEd Tanous     nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
2340c1d019a6SEd Tanous     for (const std::string& sensor : *sensorNames)
2341bacb2162SNan Zhou     {
234262598e31SEd Tanous         BMCWEB_LOG_DEBUG("Adding sensor: {}", sensor);
2343bacb2162SNan Zhou 
2344bacb2162SNan Zhou         sdbusplus::message::object_path path(sensor);
2345bacb2162SNan Zhou         std::string sensorName = path.filename();
2346bacb2162SNan Zhou         if (sensorName.empty())
2347bacb2162SNan Zhou         {
234862598e31SEd Tanous             BMCWEB_LOG_ERROR("Invalid sensor path: {}", sensor);
2349c1d019a6SEd Tanous             messages::internalError(asyncResp->res);
2350bacb2162SNan Zhou             return;
2351bacb2162SNan Zhou         }
2352c1d019a6SEd Tanous         std::string type = path.parent_path().filename();
23531516c21bSJanet Adkins         std::string id = redfish::sensor_utils::getSensorId(sensorName, type);
2354c1d019a6SEd Tanous 
23551476687dSEd Tanous         nlohmann::json::object_t member;
2356ef4c65b7SEd Tanous         member["@odata.id"] = boost::urls::format(
2357ef4c65b7SEd Tanous             "/redfish/v1/Chassis/{}/{}/{}", chassisId, chassisSubNode, id);
2358c1d019a6SEd Tanous 
2359b2ba3072SPatrick Williams         entriesArray.emplace_back(std::move(member));
2360bacb2162SNan Zhou     }
2361bacb2162SNan Zhou 
2362c1d019a6SEd Tanous     asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
236362598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassisCallback exit");
2364bacb2162SNan Zhou }
2365e6bd846dSNan Zhou 
2366ac106bf6SEd Tanous inline void handleSensorCollectionGet(
2367ac106bf6SEd Tanous     App& app, const crow::Request& req,
2368ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2369de167a6fSNan Zhou     const std::string& chassisId)
2370de167a6fSNan Zhou {
2371de167a6fSNan Zhou     query_param::QueryCapabilities capabilities = {
2372de167a6fSNan Zhou         .canDelegateExpandLevel = 1,
2373de167a6fSNan Zhou     };
2374de167a6fSNan Zhou     query_param::Query delegatedQuery;
2375ac106bf6SEd Tanous     if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
2376de167a6fSNan Zhou                                                   delegatedQuery, capabilities))
2377de167a6fSNan Zhou     {
2378de167a6fSNan Zhou         return;
2379de167a6fSNan Zhou     }
2380de167a6fSNan Zhou 
2381de167a6fSNan Zhou     if (delegatedQuery.expandType != query_param::ExpandType::None)
2382de167a6fSNan Zhou     {
2383de167a6fSNan Zhou         // we perform efficient expand.
2384ac106bf6SEd Tanous         auto sensorsAsyncResp = std::make_shared<SensorsAsyncResp>(
2385ac106bf6SEd Tanous             asyncResp, chassisId, sensors::dbus::sensorPaths,
23860c728b42SJanet Adkins             sensors::sensorsNodeStr,
2387de167a6fSNan Zhou             /*efficientExpand=*/true);
2388ac106bf6SEd Tanous         getChassisData(sensorsAsyncResp);
2389de167a6fSNan Zhou 
239062598e31SEd Tanous         BMCWEB_LOG_DEBUG(
239162598e31SEd Tanous             "SensorCollection doGet exit via efficient expand handler");
2392de167a6fSNan Zhou         return;
23930bad320cSEd Tanous     }
2394de167a6fSNan Zhou 
2395de167a6fSNan Zhou     // We get all sensors as hyperlinkes in the chassis (this
2396de167a6fSNan Zhou     // implies we reply on the default query parameters handler)
23970c728b42SJanet Adkins     getChassis(asyncResp, chassisId, sensors::sensorsNodeStr, dbus::sensorPaths,
2398ac106bf6SEd Tanous                std::bind_front(sensors::getChassisCallback, asyncResp,
23990c728b42SJanet Adkins                                chassisId, sensors::sensorsNodeStr));
2400c1d019a6SEd Tanous }
24017f1cc26dSEd Tanous 
2402*504af5a0SPatrick Williams inline void getSensorFromDbus(
2403*504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2404c1d019a6SEd Tanous     const std::string& sensorPath,
2405c1d019a6SEd Tanous     const ::dbus::utility::MapperGetObject& mapperResponse)
2406c1d019a6SEd Tanous {
2407c1d019a6SEd Tanous     if (mapperResponse.size() != 1)
2408c1d019a6SEd Tanous     {
2409c1d019a6SEd Tanous         messages::internalError(asyncResp->res);
2410c1d019a6SEd Tanous         return;
2411c1d019a6SEd Tanous     }
2412c1d019a6SEd Tanous     const auto& valueIface = *mapperResponse.begin();
2413c1d019a6SEd Tanous     const std::string& connectionName = valueIface.first;
241462598e31SEd Tanous     BMCWEB_LOG_DEBUG("Looking up {}", connectionName);
241562598e31SEd Tanous     BMCWEB_LOG_DEBUG("Path {}", sensorPath);
2416c1343bf6SKrzysztof Grobelny 
2417deae6a78SEd Tanous     ::dbus::utility::getAllProperties(
2418c1343bf6SKrzysztof Grobelny         *crow::connections::systemBus, connectionName, sensorPath, "",
2419c1d019a6SEd Tanous         [asyncResp,
24205e7e2dc5SEd Tanous          sensorPath](const boost::system::error_code& ec,
2421c1d019a6SEd Tanous                      const ::dbus::utility::DBusPropertiesMap& valuesDict) {
2422c1d019a6SEd Tanous             if (ec)
2423c1d019a6SEd Tanous             {
2424c1d019a6SEd Tanous                 messages::internalError(asyncResp->res);
2425c1d019a6SEd Tanous                 return;
2426c1d019a6SEd Tanous             }
2427c1d019a6SEd Tanous             sdbusplus::message::object_path path(sensorPath);
2428c1d019a6SEd Tanous             std::string name = path.filename();
2429c1d019a6SEd Tanous             path = path.parent_path();
2430c1d019a6SEd Tanous             std::string type = path.filename();
2431c9563608SJanet Adkins             sensor_utils::objectPropertiesToJson(
24320c728b42SJanet Adkins                 name, type, sensor_utils::ChassisSubNode::sensorsNode,
24330c728b42SJanet Adkins                 valuesDict, asyncResp->res.jsonValue, nullptr);
2434c1343bf6SKrzysztof Grobelny         });
2435de167a6fSNan Zhou }
2436de167a6fSNan Zhou 
2437e6bd846dSNan Zhou inline void handleSensorGet(App& app, const crow::Request& req,
2438c1d019a6SEd Tanous                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2439677bb756SEd Tanous                             const std::string& chassisId,
2440c1d019a6SEd Tanous                             const std::string& sensorId)
2441e6bd846dSNan Zhou {
2442c1d019a6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2443e6bd846dSNan Zhou     {
2444e6bd846dSNan Zhou         return;
2445e6bd846dSNan Zhou     }
2446c71d6125SEd Tanous     std::pair<std::string, std::string> nameType =
24471516c21bSJanet Adkins         redfish::sensor_utils::splitSensorNameAndType(sensorId);
2448c71d6125SEd Tanous     if (nameType.first.empty() || nameType.second.empty())
2449c1d019a6SEd Tanous     {
2450c1d019a6SEd Tanous         messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2451c1d019a6SEd Tanous         return;
2452c1d019a6SEd Tanous     }
2453c71d6125SEd Tanous 
2454ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2455ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/Sensors/{}", chassisId, sensorId);
2456c1d019a6SEd Tanous 
245762598e31SEd Tanous     BMCWEB_LOG_DEBUG("Sensor doGet enter");
2458e6bd846dSNan Zhou 
24592b73119cSGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
2460e6bd846dSNan Zhou         "xyz.openbmc_project.Sensor.Value"};
2461c71d6125SEd Tanous     std::string sensorPath = "/xyz/openbmc_project/sensors/" + nameType.first +
2462c71d6125SEd Tanous                              '/' + nameType.second;
2463e6bd846dSNan Zhou     // Get a list of all of the sensors that implement Sensor.Value
2464e6bd846dSNan Zhou     // and get the path and service name associated with the sensor
24652b73119cSGeorge Liu     ::dbus::utility::getDbusObject(
24662b73119cSGeorge Liu         sensorPath, interfaces,
2467aec0ec30SMyung Bae         [asyncResp, sensorId,
24682b73119cSGeorge Liu          sensorPath](const boost::system::error_code& ec,
2469c1d019a6SEd Tanous                      const ::dbus::utility::MapperGetObject& subtree) {
247062598e31SEd Tanous             BMCWEB_LOG_DEBUG("respHandler1 enter");
2471aec0ec30SMyung Bae             if (ec == boost::system::errc::io_error)
2472aec0ec30SMyung Bae             {
247362598e31SEd Tanous                 BMCWEB_LOG_WARNING("Sensor not found from getSensorPaths");
2474aec0ec30SMyung Bae                 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2475aec0ec30SMyung Bae                 return;
2476aec0ec30SMyung Bae             }
2477e6bd846dSNan Zhou             if (ec)
2478e6bd846dSNan Zhou             {
2479c1d019a6SEd Tanous                 messages::internalError(asyncResp->res);
248062598e31SEd Tanous                 BMCWEB_LOG_ERROR(
248162598e31SEd Tanous                     "Sensor getSensorPaths resp_handler: Dbus error {}", ec);
2482e6bd846dSNan Zhou                 return;
2483e6bd846dSNan Zhou             }
2484c1d019a6SEd Tanous             getSensorFromDbus(asyncResp, sensorPath, subtree);
248562598e31SEd Tanous             BMCWEB_LOG_DEBUG("respHandler1 exit");
24862b73119cSGeorge Liu         });
2487e6bd846dSNan Zhou }
2488e6bd846dSNan Zhou 
2489bacb2162SNan Zhou } // namespace sensors
2490bacb2162SNan Zhou 
24917e860f15SJohn Edward Broadbent inline void requestRoutesSensorCollection(App& app)
249295a3ecadSAnthony Wilson {
24937e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
2494ed398213SEd Tanous         .privileges(redfish::privileges::getSensorCollection)
2495002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
2496de167a6fSNan Zhou             std::bind_front(sensors::handleSensorCollectionGet, std::ref(app)));
249795a3ecadSAnthony Wilson }
249895a3ecadSAnthony Wilson 
24997e860f15SJohn Edward Broadbent inline void requestRoutesSensor(App& app)
250095a3ecadSAnthony Wilson {
25017e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/")
2502ed398213SEd Tanous         .privileges(redfish::privileges::getSensor)
2503002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
2504e6bd846dSNan Zhou             std::bind_front(sensors::handleSensorGet, std::ref(app)));
250595a3ecadSAnthony Wilson }
250695a3ecadSAnthony Wilson 
250708777fb0SLewanczyk, Dawid } // namespace redfish
2508