xref: /openbmc/bmcweb/features/redfish/lib/sensors.hpp (revision 40e9b92ec19acffb46f83a6e55b18974da5d708e)
1*40e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
2*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
408777fb0SLewanczyk, Dawid #pragma once
508777fb0SLewanczyk, Dawid 
63ccb3adbSEd Tanous #include "app.hpp"
73ccb3adbSEd Tanous #include "dbus_singleton.hpp"
87a1dbc48SGeorge Liu #include "dbus_utility.hpp"
9539d8c6bSEd Tanous #include "generated/enums/redundancy.hpp"
10aaf08ac7SMatt Simmering #include "generated/enums/resource.hpp"
113ccb3adbSEd Tanous #include "query.hpp"
123ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
1350ebd4afSEd Tanous #include "str_utility.hpp"
143ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
153ccb3adbSEd Tanous #include "utils/json_utils.hpp"
163ccb3adbSEd Tanous #include "utils/query_param.hpp"
171516c21bSJanet Adkins #include "utils/sensor_utils.hpp"
180ec8b83dSEd Tanous 
19e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
20ef4c65b7SEd Tanous #include <boost/url/format.hpp>
211e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp>
2286d89ed7SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
231214b7e7SGunnar Mills 
247a1dbc48SGeorge Liu #include <array>
251214b7e7SGunnar Mills #include <cmath>
26fe04d49cSNan Zhou #include <iterator>
27283860f5SEd Tanous #include <limits>
28fe04d49cSNan Zhou #include <map>
293544d2a7SEd Tanous #include <ranges>
30fe04d49cSNan Zhou #include <set>
3118f8f608SEd Tanous #include <string>
327a1dbc48SGeorge Liu #include <string_view>
33b5a76932SEd Tanous #include <utility>
34abf2add6SEd Tanous #include <variant>
3508777fb0SLewanczyk, Dawid 
361abe55efSEd Tanous namespace redfish
371abe55efSEd Tanous {
3808777fb0SLewanczyk, Dawid 
39a0ec28b6SAdrian Ambrożewicz namespace sensors
40a0ec28b6SAdrian Ambrożewicz {
41a0ec28b6SAdrian Ambrożewicz 
4202da7c5aSEd Tanous // clang-format off
43a0ec28b6SAdrian Ambrożewicz namespace dbus
44a0ec28b6SAdrian Ambrożewicz {
45cf9e417dSEd Tanous constexpr auto powerPaths = std::to_array<std::string_view>({
4602da7c5aSEd Tanous     "/xyz/openbmc_project/sensors/voltage",
4702da7c5aSEd Tanous     "/xyz/openbmc_project/sensors/power"
4802da7c5aSEd Tanous });
49c2bf7f99SWludzik, Jozef 
5025b54dbaSEd Tanous constexpr auto getSensorPaths(){
5125b54dbaSEd Tanous     if constexpr(BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM){
5225b54dbaSEd Tanous     return std::to_array<std::string_view>({
5302da7c5aSEd Tanous         "/xyz/openbmc_project/sensors/power",
54a0ec28b6SAdrian Ambrożewicz         "/xyz/openbmc_project/sensors/current",
557088690cSBasheer Ahmed Muddebihal         "/xyz/openbmc_project/sensors/airflow",
565deabed9SGunnar Mills         "/xyz/openbmc_project/sensors/humidity",
57e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/voltage",
58e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/fan_tach",
59e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/temperature",
60e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/fan_pwm",
61e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/altitude",
62e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/energy",
6325b54dbaSEd Tanous         "/xyz/openbmc_project/sensors/utilization"});
6425b54dbaSEd Tanous     } else {
6525b54dbaSEd Tanous       return  std::to_array<std::string_view>({"/xyz/openbmc_project/sensors/power",
6625b54dbaSEd Tanous         "/xyz/openbmc_project/sensors/current",
6725b54dbaSEd Tanous         "/xyz/openbmc_project/sensors/airflow",
6825b54dbaSEd Tanous         "/xyz/openbmc_project/sensors/humidity",
6925b54dbaSEd Tanous         "/xyz/openbmc_project/sensors/utilization"});
7025b54dbaSEd Tanous }
7125b54dbaSEd Tanous }
7225b54dbaSEd Tanous 
7325b54dbaSEd Tanous constexpr auto sensorPaths = getSensorPaths();
7402da7c5aSEd Tanous 
75cf9e417dSEd Tanous constexpr auto thermalPaths = std::to_array<std::string_view>({
7602da7c5aSEd Tanous     "/xyz/openbmc_project/sensors/fan_tach",
77a0ec28b6SAdrian Ambrożewicz     "/xyz/openbmc_project/sensors/temperature",
7802da7c5aSEd Tanous     "/xyz/openbmc_project/sensors/fan_pwm"
7902da7c5aSEd Tanous });
8002da7c5aSEd Tanous 
81c2bf7f99SWludzik, Jozef } // namespace dbus
8202da7c5aSEd Tanous // clang-format on
8302da7c5aSEd Tanous 
840c728b42SJanet Adkins constexpr std::string_view powerNodeStr = sensor_utils::chassisSubNodeToString(
850c728b42SJanet Adkins     sensor_utils::ChassisSubNode::powerNode);
860c728b42SJanet Adkins constexpr std::string_view sensorsNodeStr =
870c728b42SJanet Adkins     sensor_utils::chassisSubNodeToString(
880c728b42SJanet Adkins         sensor_utils::ChassisSubNode::sensorsNode);
890c728b42SJanet Adkins constexpr std::string_view thermalNodeStr =
900c728b42SJanet Adkins     sensor_utils::chassisSubNodeToString(
910c728b42SJanet Adkins         sensor_utils::ChassisSubNode::thermalNode);
920c728b42SJanet Adkins 
93cf9e417dSEd Tanous using sensorPair =
94cf9e417dSEd Tanous     std::pair<std::string_view, std::span<const std::string_view>>;
9502da7c5aSEd Tanous static constexpr std::array<sensorPair, 3> paths = {
960c728b42SJanet Adkins     {{sensors::powerNodeStr, dbus::powerPaths},
970c728b42SJanet Adkins      {sensors::sensorsNodeStr, dbus::sensorPaths},
980c728b42SJanet Adkins      {sensors::thermalNodeStr, dbus::thermalPaths}}};
99c2bf7f99SWludzik, Jozef 
100a0ec28b6SAdrian Ambrożewicz } // namespace sensors
101a0ec28b6SAdrian Ambrożewicz 
10208777fb0SLewanczyk, Dawid /**
103588c3f0dSKowalski, Kamil  * SensorsAsyncResp
10408777fb0SLewanczyk, Dawid  * Gathers data needed for response processing after async calls are done
10508777fb0SLewanczyk, Dawid  */
1061abe55efSEd Tanous class SensorsAsyncResp
1071abe55efSEd Tanous {
10808777fb0SLewanczyk, Dawid   public:
109a0ec28b6SAdrian Ambrożewicz     using DataCompleteCb = std::function<void(
110a0ec28b6SAdrian Ambrożewicz         const boost::beast::http::status status,
111fe04d49cSNan Zhou         const std::map<std::string, std::string>& uriToDbus)>;
112a0ec28b6SAdrian Ambrożewicz 
113a0ec28b6SAdrian Ambrożewicz     struct SensorData
114a0ec28b6SAdrian Ambrożewicz     {
115f836c1d8SEd Tanous         std::string name;
116a0ec28b6SAdrian Ambrożewicz         std::string uri;
117f836c1d8SEd Tanous         std::string dbusPath;
118a0ec28b6SAdrian Ambrożewicz     };
119a0ec28b6SAdrian Ambrożewicz 
1208a592810SEd Tanous     SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
1218d1b46d7Szhanghch05                      const std::string& chassisIdIn,
122cf9e417dSEd Tanous                      std::span<const std::string_view> typesIn,
12302da7c5aSEd Tanous                      std::string_view subNode) :
124bd79bce8SPatrick Williams         asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
125bd79bce8SPatrick Williams         chassisSubNode(subNode), efficientExpand(false)
1261214b7e7SGunnar Mills     {}
12708777fb0SLewanczyk, Dawid 
128a0ec28b6SAdrian Ambrożewicz     // Store extra data about sensor mapping and return it in callback
1298a592810SEd Tanous     SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
1308d1b46d7Szhanghch05                      const std::string& chassisIdIn,
131cf9e417dSEd Tanous                      std::span<const std::string_view> typesIn,
13202da7c5aSEd Tanous                      std::string_view subNode,
133a0ec28b6SAdrian Ambrożewicz                      DataCompleteCb&& creationComplete) :
134bd79bce8SPatrick Williams         asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
135bd79bce8SPatrick Williams         chassisSubNode(subNode), efficientExpand(false),
136bd79bce8SPatrick Williams         metadata{std::vector<SensorData>()},
137a0ec28b6SAdrian Ambrożewicz         dataComplete{std::move(creationComplete)}
138a0ec28b6SAdrian Ambrożewicz     {}
139a0ec28b6SAdrian Ambrożewicz 
140928fefb9SNan Zhou     // sensor collections expand
1418a592810SEd Tanous     SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
142928fefb9SNan Zhou                      const std::string& chassisIdIn,
143cf9e417dSEd Tanous                      std::span<const std::string_view> typesIn,
1448a592810SEd Tanous                      const std::string_view& subNode, bool efficientExpandIn) :
145bd79bce8SPatrick Williams         asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
146bd79bce8SPatrick Williams         chassisSubNode(subNode), efficientExpand(efficientExpandIn)
147928fefb9SNan Zhou     {}
148928fefb9SNan Zhou 
1491abe55efSEd Tanous     ~SensorsAsyncResp()
1501abe55efSEd Tanous     {
1518d1b46d7Szhanghch05         if (asyncResp->res.result() ==
1528d1b46d7Szhanghch05             boost::beast::http::status::internal_server_error)
1531abe55efSEd Tanous         {
1541abe55efSEd Tanous             // Reset the json object to clear out any data that made it in
1551abe55efSEd Tanous             // before the error happened todo(ed) handle error condition with
1561abe55efSEd Tanous             // proper code
1578d1b46d7Szhanghch05             asyncResp->res.jsonValue = nlohmann::json::object();
15808777fb0SLewanczyk, Dawid         }
159a0ec28b6SAdrian Ambrożewicz 
160a0ec28b6SAdrian Ambrożewicz         if (dataComplete && metadata)
161a0ec28b6SAdrian Ambrożewicz         {
162fe04d49cSNan Zhou             std::map<std::string, std::string> map;
1638d1b46d7Szhanghch05             if (asyncResp->res.result() == boost::beast::http::status::ok)
164a0ec28b6SAdrian Ambrożewicz             {
165a0ec28b6SAdrian Ambrożewicz                 for (auto& sensor : *metadata)
166a0ec28b6SAdrian Ambrożewicz                 {
167c1d019a6SEd Tanous                     map.emplace(sensor.uri, sensor.dbusPath);
168a0ec28b6SAdrian Ambrożewicz                 }
169a0ec28b6SAdrian Ambrożewicz             }
1708d1b46d7Szhanghch05             dataComplete(asyncResp->res.result(), map);
171a0ec28b6SAdrian Ambrożewicz         }
17208777fb0SLewanczyk, Dawid     }
173588c3f0dSKowalski, Kamil 
174ecd6a3a2SEd Tanous     SensorsAsyncResp(const SensorsAsyncResp&) = delete;
175ecd6a3a2SEd Tanous     SensorsAsyncResp(SensorsAsyncResp&&) = delete;
176ecd6a3a2SEd Tanous     SensorsAsyncResp& operator=(const SensorsAsyncResp&) = delete;
177ecd6a3a2SEd Tanous     SensorsAsyncResp& operator=(SensorsAsyncResp&&) = delete;
178ecd6a3a2SEd Tanous 
179a0ec28b6SAdrian Ambrożewicz     void addMetadata(const nlohmann::json& sensorObject,
180c1d019a6SEd Tanous                      const std::string& dbusPath)
181a0ec28b6SAdrian Ambrożewicz     {
182a0ec28b6SAdrian Ambrożewicz         if (metadata)
183a0ec28b6SAdrian Ambrożewicz         {
184c1d019a6SEd Tanous             metadata->emplace_back(SensorData{
185c1d019a6SEd Tanous                 sensorObject["Name"], sensorObject["@odata.id"], dbusPath});
186a0ec28b6SAdrian Ambrożewicz         }
187a0ec28b6SAdrian Ambrożewicz     }
188a0ec28b6SAdrian Ambrożewicz 
189a0ec28b6SAdrian Ambrożewicz     void updateUri(const std::string& name, const std::string& uri)
190a0ec28b6SAdrian Ambrożewicz     {
191a0ec28b6SAdrian Ambrożewicz         if (metadata)
192a0ec28b6SAdrian Ambrożewicz         {
193a0ec28b6SAdrian Ambrożewicz             for (auto& sensor : *metadata)
194a0ec28b6SAdrian Ambrożewicz             {
195a0ec28b6SAdrian Ambrożewicz                 if (sensor.name == name)
196a0ec28b6SAdrian Ambrożewicz                 {
197a0ec28b6SAdrian Ambrożewicz                     sensor.uri = uri;
198a0ec28b6SAdrian Ambrożewicz                 }
199a0ec28b6SAdrian Ambrożewicz             }
200a0ec28b6SAdrian Ambrożewicz         }
201a0ec28b6SAdrian Ambrożewicz     }
202a0ec28b6SAdrian Ambrożewicz 
2038d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
204a0ec28b6SAdrian Ambrożewicz     const std::string chassisId;
205cf9e417dSEd Tanous     const std::span<const std::string_view> types;
206a0ec28b6SAdrian Ambrożewicz     const std::string chassisSubNode;
207928fefb9SNan Zhou     const bool efficientExpand;
208a0ec28b6SAdrian Ambrożewicz 
209a0ec28b6SAdrian Ambrożewicz   private:
210a0ec28b6SAdrian Ambrożewicz     std::optional<std::vector<SensorData>> metadata;
211a0ec28b6SAdrian Ambrożewicz     DataCompleteCb dataComplete;
21208777fb0SLewanczyk, Dawid };
21308777fb0SLewanczyk, Dawid 
214c9563608SJanet Adkins using InventoryItem = sensor_utils::InventoryItem;
215adc4f0dbSShawn McCarney 
216adc4f0dbSShawn McCarney /**
217413961deSRichard Marian Thomaiyar  * @brief Get objects with connection necessary for sensors
218588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp Pointer to object holding response data
21908777fb0SLewanczyk, Dawid  * @param sensorNames Sensors retrieved from chassis
22008777fb0SLewanczyk, Dawid  * @param callback Callback for processing gathered connections
22108777fb0SLewanczyk, Dawid  */
22208777fb0SLewanczyk, Dawid template <typename Callback>
223413961deSRichard Marian Thomaiyar void getObjectsWithConnection(
22481ce609eSEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
225fe04d49cSNan Zhou     const std::shared_ptr<std::set<std::string>>& sensorNames,
2261abe55efSEd Tanous     Callback&& callback)
2271abe55efSEd Tanous {
22862598e31SEd Tanous     BMCWEB_LOG_DEBUG("getObjectsWithConnection enter");
22903b5bae3SJames Feist     const std::string path = "/xyz/openbmc_project/sensors";
230e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
23108777fb0SLewanczyk, Dawid         "xyz.openbmc_project.Sensor.Value"};
23208777fb0SLewanczyk, Dawid 
233e99073f5SGeorge Liu     // Make call to ObjectMapper to find all sensors objects
234e99073f5SGeorge Liu     dbus::utility::getSubTree(
235e99073f5SGeorge Liu         path, 2, interfaces,
2368cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), sensorsAsyncResp,
237e99073f5SGeorge Liu          sensorNames](const boost::system::error_code& ec,
238002d39b4SEd Tanous                       const dbus::utility::MapperGetSubTreeResponse& subtree) {
239e99073f5SGeorge Liu             // Response handler for parsing objects subtree
24062598e31SEd Tanous             BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler enter");
2411abe55efSEd Tanous             if (ec)
2421abe55efSEd Tanous             {
2438d1b46d7Szhanghch05                 messages::internalError(sensorsAsyncResp->asyncResp->res);
24462598e31SEd Tanous                 BMCWEB_LOG_ERROR(
24562598e31SEd Tanous                     "getObjectsWithConnection resp_handler: Dbus error {}", ec);
24608777fb0SLewanczyk, Dawid                 return;
24708777fb0SLewanczyk, Dawid             }
24808777fb0SLewanczyk, Dawid 
24962598e31SEd Tanous             BMCWEB_LOG_DEBUG("Found {} subtrees", subtree.size());
25008777fb0SLewanczyk, Dawid 
251bd79bce8SPatrick Williams             // Make unique list of connections only for requested sensor types
252bd79bce8SPatrick Williams             // and found in the chassis
253fe04d49cSNan Zhou             std::set<std::string> connections;
254413961deSRichard Marian Thomaiyar             std::set<std::pair<std::string, std::string>> objectsWithConnection;
25508777fb0SLewanczyk, Dawid 
25662598e31SEd Tanous             BMCWEB_LOG_DEBUG("sensorNames list count: {}", sensorNames->size());
25749c53ac9SJohnathan Mantey             for (const std::string& tsensor : *sensorNames)
2581abe55efSEd Tanous             {
25962598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Sensor to find: {}", tsensor);
26008777fb0SLewanczyk, Dawid             }
26108777fb0SLewanczyk, Dawid 
262bd79bce8SPatrick Williams             for (const std::pair<std::string,
263bd79bce8SPatrick Williams                                  std::vector<std::pair<
264bd79bce8SPatrick Williams                                      std::string, std::vector<std::string>>>>&
2651abe55efSEd Tanous                      object : subtree)
2661abe55efSEd Tanous             {
26749c53ac9SJohnathan Mantey                 if (sensorNames->find(object.first) != sensorNames->end())
2681abe55efSEd Tanous                 {
26949c53ac9SJohnathan Mantey                     for (const std::pair<std::string, std::vector<std::string>>&
2701abe55efSEd Tanous                              objData : object.second)
2711abe55efSEd Tanous                     {
272bd79bce8SPatrick Williams                         BMCWEB_LOG_DEBUG("Adding connection: {}",
273bd79bce8SPatrick Williams                                          objData.first);
27408777fb0SLewanczyk, Dawid                         connections.insert(objData.first);
275de629b6eSShawn McCarney                         objectsWithConnection.insert(
276de629b6eSShawn McCarney                             std::make_pair(object.first, objData.first));
27708777fb0SLewanczyk, Dawid                     }
27808777fb0SLewanczyk, Dawid                 }
27908777fb0SLewanczyk, Dawid             }
28062598e31SEd Tanous             BMCWEB_LOG_DEBUG("Found {} connections", connections.size());
281413961deSRichard Marian Thomaiyar             callback(std::move(connections), std::move(objectsWithConnection));
28262598e31SEd Tanous             BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler exit");
283e99073f5SGeorge Liu         });
28462598e31SEd Tanous     BMCWEB_LOG_DEBUG("getObjectsWithConnection exit");
285413961deSRichard Marian Thomaiyar }
286413961deSRichard Marian Thomaiyar 
287413961deSRichard Marian Thomaiyar /**
288413961deSRichard Marian Thomaiyar  * @brief Create connections necessary for sensors
289413961deSRichard Marian Thomaiyar  * @param SensorsAsyncResp Pointer to object holding response data
290413961deSRichard Marian Thomaiyar  * @param sensorNames Sensors retrieved from chassis
291413961deSRichard Marian Thomaiyar  * @param callback Callback for processing gathered connections
292413961deSRichard Marian Thomaiyar  */
293413961deSRichard Marian Thomaiyar template <typename Callback>
294daadfb2eSEd Tanous void getConnections(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
295daadfb2eSEd Tanous                     const std::shared_ptr<std::set<std::string>>& sensorNames,
296413961deSRichard Marian Thomaiyar                     Callback&& callback)
297413961deSRichard Marian Thomaiyar {
298413961deSRichard Marian Thomaiyar     auto objectsWithConnectionCb =
2998cb2c024SEd Tanous         [callback = std::forward<Callback>(callback)](
3008cb2c024SEd Tanous             const std::set<std::string>& connections,
301413961deSRichard Marian Thomaiyar             const std::set<std::pair<std::string, std::string>>&
3023174e4dfSEd Tanous             /*objectsWithConnection*/) { callback(connections); };
30381ce609eSEd Tanous     getObjectsWithConnection(sensorsAsyncResp, sensorNames,
304413961deSRichard Marian Thomaiyar                              std::move(objectsWithConnectionCb));
30508777fb0SLewanczyk, Dawid }
30608777fb0SLewanczyk, Dawid 
30708777fb0SLewanczyk, Dawid /**
30849c53ac9SJohnathan Mantey  * @brief Shrinks the list of sensors for processing
30949c53ac9SJohnathan Mantey  * @param SensorsAysncResp  The class holding the Redfish response
31049c53ac9SJohnathan Mantey  * @param allSensors  A list of all the sensors associated to the
31149c53ac9SJohnathan Mantey  * chassis element (i.e. baseboard, front panel, etc...)
31249c53ac9SJohnathan Mantey  * @param activeSensors A list that is a reduction of the incoming
31349c53ac9SJohnathan Mantey  * allSensors list.  Eliminate Thermal sensors when a Power request is
31449c53ac9SJohnathan Mantey  * made, and eliminate Power sensors when a Thermal request is made.
31549c53ac9SJohnathan Mantey  */
31623a21a1cSEd Tanous inline void reduceSensorList(
3177f1cc26dSEd Tanous     crow::Response& res, std::string_view chassisSubNode,
318cf9e417dSEd Tanous     std::span<const std::string_view> sensorTypes,
31949c53ac9SJohnathan Mantey     const std::vector<std::string>* allSensors,
320fe04d49cSNan Zhou     const std::shared_ptr<std::set<std::string>>& activeSensors)
32149c53ac9SJohnathan Mantey {
32249c53ac9SJohnathan Mantey     if ((allSensors == nullptr) || (activeSensors == nullptr))
32349c53ac9SJohnathan Mantey     {
3247f1cc26dSEd Tanous         messages::resourceNotFound(res, chassisSubNode,
3250c728b42SJanet Adkins                                    chassisSubNode == sensors::thermalNodeStr
326a0ec28b6SAdrian Ambrożewicz                                        ? "Temperatures"
32749c53ac9SJohnathan Mantey                                        : "Voltages");
32849c53ac9SJohnathan Mantey 
32949c53ac9SJohnathan Mantey         return;
33049c53ac9SJohnathan Mantey     }
33149c53ac9SJohnathan Mantey     if (allSensors->empty())
33249c53ac9SJohnathan Mantey     {
33349c53ac9SJohnathan Mantey         // Nothing to do, the activeSensors object is also empty
33449c53ac9SJohnathan Mantey         return;
33549c53ac9SJohnathan Mantey     }
33649c53ac9SJohnathan Mantey 
3377f1cc26dSEd Tanous     for (std::string_view type : sensorTypes)
33849c53ac9SJohnathan Mantey     {
33949c53ac9SJohnathan Mantey         for (const std::string& sensor : *allSensors)
34049c53ac9SJohnathan Mantey         {
34111ba3979SEd Tanous             if (sensor.starts_with(type))
34249c53ac9SJohnathan Mantey             {
34349c53ac9SJohnathan Mantey                 activeSensors->emplace(sensor);
34449c53ac9SJohnathan Mantey             }
34549c53ac9SJohnathan Mantey         }
34649c53ac9SJohnathan Mantey     }
34749c53ac9SJohnathan Mantey }
34849c53ac9SJohnathan Mantey 
3497f1cc26dSEd Tanous /*
3507f1cc26dSEd Tanous  *Populates the top level collection for a given subnode.  Populates
3517f1cc26dSEd Tanous  *SensorCollection, Power, or Thermal schemas.
3527f1cc26dSEd Tanous  *
3537f1cc26dSEd Tanous  * */
3547f1cc26dSEd Tanous inline void populateChassisNode(nlohmann::json& jsonValue,
3557f1cc26dSEd Tanous                                 std::string_view chassisSubNode)
3567f1cc26dSEd Tanous {
3570c728b42SJanet Adkins     if (chassisSubNode == sensors::powerNodeStr)
3587f1cc26dSEd Tanous     {
3597f1cc26dSEd Tanous         jsonValue["@odata.type"] = "#Power.v1_5_2.Power";
3607f1cc26dSEd Tanous     }
3610c728b42SJanet Adkins     else if (chassisSubNode == sensors::thermalNodeStr)
3627f1cc26dSEd Tanous     {
3637f1cc26dSEd Tanous         jsonValue["@odata.type"] = "#Thermal.v1_4_0.Thermal";
3647f1cc26dSEd Tanous         jsonValue["Fans"] = nlohmann::json::array();
3657f1cc26dSEd Tanous         jsonValue["Temperatures"] = nlohmann::json::array();
3667f1cc26dSEd Tanous     }
3670c728b42SJanet Adkins     else if (chassisSubNode == sensors::sensorsNodeStr)
3687f1cc26dSEd Tanous     {
3697f1cc26dSEd Tanous         jsonValue["@odata.type"] = "#SensorCollection.SensorCollection";
3707f1cc26dSEd Tanous         jsonValue["Description"] = "Collection of Sensors for this Chassis";
3717f1cc26dSEd Tanous         jsonValue["Members"] = nlohmann::json::array();
3727f1cc26dSEd Tanous         jsonValue["Members@odata.count"] = 0;
3737f1cc26dSEd Tanous     }
3747f1cc26dSEd Tanous 
3750c728b42SJanet Adkins     if (chassisSubNode != sensors::sensorsNodeStr)
3767f1cc26dSEd Tanous     {
3777f1cc26dSEd Tanous         jsonValue["Id"] = chassisSubNode;
3787f1cc26dSEd Tanous     }
3797f1cc26dSEd Tanous     jsonValue["Name"] = chassisSubNode;
3807f1cc26dSEd Tanous }
3817f1cc26dSEd Tanous 
38249c53ac9SJohnathan Mantey /**
38308777fb0SLewanczyk, Dawid  * @brief Retrieves requested chassis sensors and redundancy data from DBus .
384588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
38508777fb0SLewanczyk, Dawid  * @param callback  Callback for next step in gathered sensor processing
38608777fb0SLewanczyk, Dawid  */
38708777fb0SLewanczyk, Dawid template <typename Callback>
3887f1cc26dSEd Tanous void getChassis(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3897f1cc26dSEd Tanous                 std::string_view chassisId, std::string_view chassisSubNode,
390cf9e417dSEd Tanous                 std::span<const std::string_view> sensorTypes,
391cf9e417dSEd Tanous                 Callback&& callback)
3921abe55efSEd Tanous {
39362598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassis enter");
3947a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
39549c53ac9SJohnathan Mantey         "xyz.openbmc_project.Inventory.Item.Board",
396adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Item.Chassis"};
3977a1dbc48SGeorge Liu 
3987a1dbc48SGeorge Liu     // Get the Chassis Collection
3997a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
4007a1dbc48SGeorge Liu         "/xyz/openbmc_project/inventory", 0, interfaces,
4018cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), asyncResp,
4027f1cc26dSEd Tanous          chassisIdStr{std::string(chassisId)},
4034e0d8789SEd Tanous          chassisSubNode{std::string(chassisSubNode)},
4044e0d8789SEd Tanous          sensorTypes](const boost::system::error_code& ec,
4054e0d8789SEd Tanous                       const dbus::utility::MapperGetSubTreePathsResponse&
4064e0d8789SEd Tanous                           chassisPaths) mutable {
40762598e31SEd Tanous             BMCWEB_LOG_DEBUG("getChassis respHandler enter");
4081abe55efSEd Tanous             if (ec)
4091abe55efSEd Tanous             {
41062598e31SEd Tanous                 BMCWEB_LOG_ERROR("getChassis respHandler DBUS error: {}", ec);
4117f1cc26dSEd Tanous                 messages::internalError(asyncResp->res);
41208777fb0SLewanczyk, Dawid                 return;
41308777fb0SLewanczyk, Dawid             }
41449c53ac9SJohnathan Mantey             const std::string* chassisPath = nullptr;
41549c53ac9SJohnathan Mantey             for (const std::string& chassis : chassisPaths)
4161abe55efSEd Tanous             {
41728aa8de5SGeorge Liu                 sdbusplus::message::object_path path(chassis);
418f8fe53e7SEd Tanous                 std::string chassisName = path.filename();
41928aa8de5SGeorge Liu                 if (chassisName.empty())
4201abe55efSEd Tanous                 {
42162598e31SEd Tanous                     BMCWEB_LOG_ERROR("Failed to find '/' in {}", chassis);
422daf36e2eSEd Tanous                     continue;
423daf36e2eSEd Tanous                 }
4247f1cc26dSEd Tanous                 if (chassisName == chassisIdStr)
4251abe55efSEd Tanous                 {
42649c53ac9SJohnathan Mantey                     chassisPath = &chassis;
42749c53ac9SJohnathan Mantey                     break;
428daf36e2eSEd Tanous                 }
42949c53ac9SJohnathan Mantey             }
43049c53ac9SJohnathan Mantey             if (chassisPath == nullptr)
4311abe55efSEd Tanous             {
432bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res, "Chassis",
433bd79bce8SPatrick Williams                                            chassisIdStr);
43449c53ac9SJohnathan Mantey                 return;
4351abe55efSEd Tanous             }
4367f1cc26dSEd Tanous             populateChassisNode(asyncResp->res.jsonValue, chassisSubNode);
43708777fb0SLewanczyk, Dawid 
438ef4c65b7SEd Tanous             asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
439ef4c65b7SEd Tanous                 "/redfish/v1/Chassis/{}/{}", chassisIdStr, chassisSubNode);
44095a3ecadSAnthony Wilson 
4418fb49dd6SShawn McCarney             // Get the list of all sensors for this Chassis element
4428fb49dd6SShawn McCarney             std::string sensorPath = *chassisPath + "/all_sensors";
4436c3e9451SGeorge Liu             dbus::utility::getAssociationEndPoints(
4444e0d8789SEd Tanous                 sensorPath, [asyncResp, chassisSubNode, sensorTypes,
4454e0d8789SEd Tanous                              callback = std::forward<Callback>(callback)](
4468b24275dSEd Tanous                                 const boost::system::error_code& ec2,
4474e0d8789SEd Tanous                                 const dbus::utility::MapperEndPoints&
4484e0d8789SEd Tanous                                     nodeSensorList) mutable {
4498b24275dSEd Tanous                     if (ec2)
45049c53ac9SJohnathan Mantey                     {
4518b24275dSEd Tanous                         if (ec2.value() != EBADR)
45249c53ac9SJohnathan Mantey                         {
4537f1cc26dSEd Tanous                             messages::internalError(asyncResp->res);
45449c53ac9SJohnathan Mantey                             return;
45549c53ac9SJohnathan Mantey                         }
45649c53ac9SJohnathan Mantey                     }
457bd79bce8SPatrick Williams                     const std::shared_ptr<std::set<std::string>>
458bd79bce8SPatrick Williams                         culledSensorList =
459fe04d49cSNan Zhou                             std::make_shared<std::set<std::string>>();
460bd79bce8SPatrick Williams                     reduceSensorList(asyncResp->res, chassisSubNode,
461bd79bce8SPatrick Williams                                      sensorTypes, &nodeSensorList,
462bd79bce8SPatrick Williams                                      culledSensorList);
463bd79bce8SPatrick Williams                     BMCWEB_LOG_DEBUG("Finishing with {}",
464bd79bce8SPatrick Williams                                      culledSensorList->size());
46549c53ac9SJohnathan Mantey                     callback(culledSensorList);
4661e1e598dSJonathan Doman                 });
4677a1dbc48SGeorge Liu         });
46862598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassis exit");
46908777fb0SLewanczyk, Dawid }
47008777fb0SLewanczyk, Dawid 
47108777fb0SLewanczyk, Dawid /**
4721d7c0054SEd Tanous  * @brief Builds a json sensor representation of a sensor.
4731d7c0054SEd Tanous  * @param sensorName  The name of the sensor to be built
4741d7c0054SEd Tanous  * @param sensorType  The type (temperature, fan_tach, etc) of the sensor to
4751d7c0054SEd Tanous  * build
4768ece0e45SEd Tanous  * @param chassisSubNode The subnode (thermal, sensor, etc) of the sensor
4771d7c0054SEd Tanous  * @param interfacesDict  A dictionary of the interfaces and properties of said
4781d7c0054SEd Tanous  * interfaces to be built from
4791d7c0054SEd Tanous  * @param sensorJson  The json object to fill
4801d7c0054SEd Tanous  * @param inventoryItem D-Bus inventory item associated with the sensor.  Will
4811d7c0054SEd Tanous  * be nullptr if no associated inventory item was found.
4821d7c0054SEd Tanous  */
4831d7c0054SEd Tanous inline void objectInterfacesToJson(
4841d7c0054SEd Tanous     const std::string& sensorName, const std::string& sensorType,
4850c728b42SJanet Adkins     const sensor_utils::ChassisSubNode chassisSubNode,
48680f79a40SMichael Shen     const dbus::utility::DBusInterfacesMap& interfacesDict,
4871d7c0054SEd Tanous     nlohmann::json& sensorJson, InventoryItem* inventoryItem)
4881d7c0054SEd Tanous {
4891d7c0054SEd Tanous     for (const auto& [interface, valuesDict] : interfacesDict)
4901d7c0054SEd Tanous     {
491c9563608SJanet Adkins         sensor_utils::objectPropertiesToJson(
492c9563608SJanet Adkins             sensorName, sensorType, chassisSubNode, valuesDict, sensorJson,
493c9563608SJanet Adkins             inventoryItem);
4941d7c0054SEd Tanous     }
49562598e31SEd Tanous     BMCWEB_LOG_DEBUG("Added sensor {}", sensorName);
4961d7c0054SEd Tanous }
4971d7c0054SEd Tanous 
498b5a76932SEd Tanous inline void populateFanRedundancy(
499b5a76932SEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
5008bd25ccdSJames Feist {
501e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
502e99073f5SGeorge Liu         "xyz.openbmc_project.Control.FanRedundancy"};
503e99073f5SGeorge Liu     dbus::utility::getSubTree(
504e99073f5SGeorge Liu         "/xyz/openbmc_project/control", 2, interfaces,
505b9d36b47SEd Tanous         [sensorsAsyncResp](
506e99073f5SGeorge Liu             const boost::system::error_code& ec,
507b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& resp) {
5088bd25ccdSJames Feist             if (ec)
5098bd25ccdSJames Feist             {
5108bd25ccdSJames Feist                 return; // don't have to have this interface
5118bd25ccdSJames Feist             }
5126c3e9451SGeorge Liu             for (const std::pair<std::string, dbus::utility::MapperServiceMap>&
513e278c18fSEd Tanous                      pathPair : resp)
5148bd25ccdSJames Feist             {
515e278c18fSEd Tanous                 const std::string& path = pathPair.first;
516bd79bce8SPatrick Williams                 const dbus::utility::MapperServiceMap& objDict =
517bd79bce8SPatrick Williams                     pathPair.second;
5188bd25ccdSJames Feist                 if (objDict.empty())
5198bd25ccdSJames Feist                 {
5208bd25ccdSJames Feist                     continue; // this should be impossible
5218bd25ccdSJames Feist                 }
5228bd25ccdSJames Feist 
5238bd25ccdSJames Feist                 const std::string& owner = objDict.begin()->first;
5246c3e9451SGeorge Liu                 dbus::utility::getAssociationEndPoints(
5256c3e9451SGeorge Liu                     path + "/chassis",
5266c3e9451SGeorge Liu                     [path, owner, sensorsAsyncResp](
5278b24275dSEd Tanous                         const boost::system::error_code& ec2,
5286c3e9451SGeorge Liu                         const dbus::utility::MapperEndPoints& endpoints) {
5298b24275dSEd Tanous                         if (ec2)
5308bd25ccdSJames Feist                         {
5318bd25ccdSJames Feist                             return; // if they don't have an association we
5328bd25ccdSJames Feist                                     // can't tell what chassis is
5338bd25ccdSJames Feist                         }
5343544d2a7SEd Tanous                         auto found = std::ranges::find_if(
535bd79bce8SPatrick Williams                             endpoints,
536bd79bce8SPatrick Williams                             [sensorsAsyncResp](const std::string& entry) {
537bd79bce8SPatrick Williams                                 return entry.find(
538bd79bce8SPatrick Williams                                            sensorsAsyncResp->chassisId) !=
5398bd25ccdSJames Feist                                        std::string::npos;
5408bd25ccdSJames Feist                             });
5418bd25ccdSJames Feist 
5421e1e598dSJonathan Doman                         if (found == endpoints.end())
5438bd25ccdSJames Feist                         {
5448bd25ccdSJames Feist                             return;
5458bd25ccdSJames Feist                         }
546deae6a78SEd Tanous                         dbus::utility::getAllProperties(
54786d89ed7SKrzysztof Grobelny                             *crow::connections::systemBus, owner, path,
54886d89ed7SKrzysztof Grobelny                             "xyz.openbmc_project.Control.FanRedundancy",
5498bd25ccdSJames Feist                             [path, sensorsAsyncResp](
5508b24275dSEd Tanous                                 const boost::system::error_code& ec3,
55186d89ed7SKrzysztof Grobelny                                 const dbus::utility::DBusPropertiesMap& ret) {
5528b24275dSEd Tanous                                 if (ec3)
5538bd25ccdSJames Feist                                 {
5548bd25ccdSJames Feist                                     return; // don't have to have this
5558bd25ccdSJames Feist                                             // interface
5568bd25ccdSJames Feist                                 }
5578bd25ccdSJames Feist 
55886d89ed7SKrzysztof Grobelny                                 const uint8_t* allowedFailures = nullptr;
559bd79bce8SPatrick Williams                                 const std::vector<std::string>* collection =
560bd79bce8SPatrick Williams                                     nullptr;
56186d89ed7SKrzysztof Grobelny                                 const std::string* status = nullptr;
56286d89ed7SKrzysztof Grobelny 
563bd79bce8SPatrick Williams                                 const bool success =
564bd79bce8SPatrick Williams                                     sdbusplus::unpackPropertiesNoThrow(
56586d89ed7SKrzysztof Grobelny                                         dbus_utils::UnpackErrorPrinter(), ret,
566bd79bce8SPatrick Williams                                         "AllowedFailures", allowedFailures,
567bd79bce8SPatrick Williams                                         "Collection", collection, "Status",
568bd79bce8SPatrick Williams                                         status);
56986d89ed7SKrzysztof Grobelny 
57086d89ed7SKrzysztof Grobelny                                 if (!success)
57186d89ed7SKrzysztof Grobelny                                 {
57286d89ed7SKrzysztof Grobelny                                     messages::internalError(
57386d89ed7SKrzysztof Grobelny                                         sensorsAsyncResp->asyncResp->res);
57486d89ed7SKrzysztof Grobelny                                     return;
57586d89ed7SKrzysztof Grobelny                                 }
57686d89ed7SKrzysztof Grobelny 
577bd79bce8SPatrick Williams                                 if (allowedFailures == nullptr ||
578bd79bce8SPatrick Williams                                     collection == nullptr || status == nullptr)
5798bd25ccdSJames Feist                                 {
580bd79bce8SPatrick Williams                                     BMCWEB_LOG_ERROR(
581bd79bce8SPatrick Williams                                         "Invalid redundancy interface");
5828bd25ccdSJames Feist                                     messages::internalError(
5838d1b46d7Szhanghch05                                         sensorsAsyncResp->asyncResp->res);
5848bd25ccdSJames Feist                                     return;
5858bd25ccdSJames Feist                                 }
5868bd25ccdSJames Feist 
587bd79bce8SPatrick Williams                                 sdbusplus::message::object_path objectPath(
588bd79bce8SPatrick Williams                                     path);
58928aa8de5SGeorge Liu                                 std::string name = objectPath.filename();
59028aa8de5SGeorge Liu                                 if (name.empty())
5918bd25ccdSJames Feist                                 {
5928bd25ccdSJames Feist                                     // this should be impossible
5938bd25ccdSJames Feist                                     messages::internalError(
5948d1b46d7Szhanghch05                                         sensorsAsyncResp->asyncResp->res);
5958bd25ccdSJames Feist                                     return;
5968bd25ccdSJames Feist                                 }
59718f8f608SEd Tanous                                 std::ranges::replace(name, '_', ' ');
5988bd25ccdSJames Feist 
5998bd25ccdSJames Feist                                 std::string health;
6008bd25ccdSJames Feist 
60111ba3979SEd Tanous                                 if (status->ends_with("Full"))
6028bd25ccdSJames Feist                                 {
6038bd25ccdSJames Feist                                     health = "OK";
6048bd25ccdSJames Feist                                 }
60511ba3979SEd Tanous                                 else if (status->ends_with("Degraded"))
6068bd25ccdSJames Feist                                 {
6078bd25ccdSJames Feist                                     health = "Warning";
6088bd25ccdSJames Feist                                 }
6098bd25ccdSJames Feist                                 else
6108bd25ccdSJames Feist                                 {
6118bd25ccdSJames Feist                                     health = "Critical";
6128bd25ccdSJames Feist                                 }
6131476687dSEd Tanous                                 nlohmann::json::array_t redfishCollection;
6148bd25ccdSJames Feist                                 const auto& fanRedfish =
615bd79bce8SPatrick Williams                                     sensorsAsyncResp->asyncResp->res
616bd79bce8SPatrick Williams                                         .jsonValue["Fans"];
6178bd25ccdSJames Feist                                 for (const std::string& item : *collection)
6188bd25ccdSJames Feist                                 {
619bd79bce8SPatrick Williams                                     sdbusplus::message::object_path itemPath(
620bd79bce8SPatrick Williams                                         item);
6218a592810SEd Tanous                                     std::string itemName = itemPath.filename();
62228aa8de5SGeorge Liu                                     if (itemName.empty())
62328aa8de5SGeorge Liu                                     {
62428aa8de5SGeorge Liu                                         continue;
62528aa8de5SGeorge Liu                                     }
6268bd25ccdSJames Feist                                     /*
6278bd25ccdSJames Feist                                     todo(ed): merge patch that fixes the names
6288bd25ccdSJames Feist                                     std::replace(itemName.begin(),
6298bd25ccdSJames Feist                                                  itemName.end(), '_', ' ');*/
6303544d2a7SEd Tanous                                     auto schemaItem = std::ranges::find_if(
631bd79bce8SPatrick Williams                                         fanRedfish,
632bd79bce8SPatrick Williams                                         [itemName](const nlohmann::json& fan) {
6333e35c761SGeorge Liu                                             return fan["Name"] == itemName;
6348bd25ccdSJames Feist                                         });
6358bd25ccdSJames Feist                                     if (schemaItem != fanRedfish.end())
6368bd25ccdSJames Feist                                     {
6378a592810SEd Tanous                                         nlohmann::json::object_t collectionId;
6388a592810SEd Tanous                                         collectionId["@odata.id"] =
6391476687dSEd Tanous                                             (*schemaItem)["@odata.id"];
6401476687dSEd Tanous                                         redfishCollection.emplace_back(
6418a592810SEd Tanous                                             std::move(collectionId));
6428bd25ccdSJames Feist                                     }
6438bd25ccdSJames Feist                                     else
6448bd25ccdSJames Feist                                     {
645bd79bce8SPatrick Williams                                         BMCWEB_LOG_ERROR(
646bd79bce8SPatrick Williams                                             "failed to find fan in schema");
6478bd25ccdSJames Feist                                         messages::internalError(
6488d1b46d7Szhanghch05                                             sensorsAsyncResp->asyncResp->res);
6498bd25ccdSJames Feist                                         return;
6508bd25ccdSJames Feist                                     }
6518bd25ccdSJames Feist                                 }
6528bd25ccdSJames Feist 
653bd79bce8SPatrick Williams                                 size_t minNumNeeded =
654bd79bce8SPatrick Williams                                     collection->empty()
65526f6976fSEd Tanous                                         ? 0
656bd79bce8SPatrick Williams                                         : collection->size() - *allowedFailures;
657bd79bce8SPatrick Williams                                 nlohmann::json& jResp =
658bd79bce8SPatrick Williams                                     sensorsAsyncResp->asyncResp->res
6598bd25ccdSJames Feist                                         .jsonValue["Redundancy"];
6601476687dSEd Tanous 
6611476687dSEd Tanous                                 nlohmann::json::object_t redundancy;
662bd79bce8SPatrick Williams                                 boost::urls::url url = boost::urls::format(
663bd79bce8SPatrick Williams                                     "/redfish/v1/Chassis/{}/{}",
664ef4c65b7SEd Tanous                                     sensorsAsyncResp->chassisId,
665eddfc437SWilly Tu                                     sensorsAsyncResp->chassisSubNode);
666bd79bce8SPatrick Williams                                 url.set_fragment(
667bd79bce8SPatrick Williams                                     ("/Redundancy"_json_pointer / jResp.size())
668eddfc437SWilly Tu                                         .to_string());
669eddfc437SWilly Tu                                 redundancy["@odata.id"] = std::move(url);
670bd79bce8SPatrick Williams                                 redundancy["@odata.type"] =
671bd79bce8SPatrick Williams                                     "#Redundancy.v1_3_2.Redundancy";
6721476687dSEd Tanous                                 redundancy["MinNumNeeded"] = minNumNeeded;
673bd79bce8SPatrick Williams                                 redundancy["Mode"] =
674bd79bce8SPatrick Williams                                     redundancy::RedundancyType::NPlusM;
6751476687dSEd Tanous                                 redundancy["Name"] = name;
6761476687dSEd Tanous                                 redundancy["RedundancySet"] = redfishCollection;
6771476687dSEd Tanous                                 redundancy["Status"]["Health"] = health;
678bd79bce8SPatrick Williams                                 redundancy["Status"]["State"] =
679bd79bce8SPatrick Williams                                     resource::State::Enabled;
6801476687dSEd Tanous 
681b2ba3072SPatrick Williams                                 jResp.emplace_back(std::move(redundancy));
68286d89ed7SKrzysztof Grobelny                             });
6831e1e598dSJonathan Doman                     });
6848bd25ccdSJames Feist             }
685e99073f5SGeorge Liu         });
6868bd25ccdSJames Feist }
6878bd25ccdSJames Feist 
688b5a76932SEd Tanous inline void
68981ce609eSEd Tanous     sortJSONResponse(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
69049c53ac9SJohnathan Mantey {
6918d1b46d7Szhanghch05     nlohmann::json& response = sensorsAsyncResp->asyncResp->res.jsonValue;
69249c53ac9SJohnathan Mantey     std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
6930c728b42SJanet Adkins     if (sensorsAsyncResp->chassisSubNode == sensors::powerNodeStr)
69449c53ac9SJohnathan Mantey     {
69549c53ac9SJohnathan Mantey         sensorHeaders = {"Voltages", "PowerSupplies"};
69649c53ac9SJohnathan Mantey     }
69749c53ac9SJohnathan Mantey     for (const std::string& sensorGroup : sensorHeaders)
69849c53ac9SJohnathan Mantey     {
69949c53ac9SJohnathan Mantey         nlohmann::json::iterator entry = response.find(sensorGroup);
7004e196b9aSEd Tanous         if (entry == response.end())
70149c53ac9SJohnathan Mantey         {
7024e196b9aSEd Tanous             continue;
7034e196b9aSEd Tanous         }
7044e196b9aSEd Tanous         nlohmann::json::array_t* arr =
7054e196b9aSEd Tanous             entry->get_ptr<nlohmann::json::array_t*>();
7064e196b9aSEd Tanous         if (arr == nullptr)
7074e196b9aSEd Tanous         {
7084e196b9aSEd Tanous             continue;
7094e196b9aSEd Tanous         }
7104e196b9aSEd Tanous         json_util::sortJsonArrayByKey(*arr, "Name");
71149c53ac9SJohnathan Mantey 
71249c53ac9SJohnathan Mantey         // add the index counts to the end of each entry
71349c53ac9SJohnathan Mantey         size_t count = 0;
71449c53ac9SJohnathan Mantey         for (nlohmann::json& sensorJson : *entry)
71549c53ac9SJohnathan Mantey         {
71649c53ac9SJohnathan Mantey             nlohmann::json::iterator odata = sensorJson.find("@odata.id");
71749c53ac9SJohnathan Mantey             if (odata == sensorJson.end())
71849c53ac9SJohnathan Mantey             {
71949c53ac9SJohnathan Mantey                 continue;
72049c53ac9SJohnathan Mantey             }
72149c53ac9SJohnathan Mantey             std::string* value = odata->get_ptr<std::string*>();
72249c53ac9SJohnathan Mantey             if (value != nullptr)
72349c53ac9SJohnathan Mantey             {
724eddfc437SWilly Tu                 *value += "/" + std::to_string(count);
7253e35c761SGeorge Liu                 sensorJson["MemberId"] = std::to_string(count);
72649c53ac9SJohnathan Mantey                 count++;
72781ce609eSEd Tanous                 sensorsAsyncResp->updateUri(sensorJson["Name"], *value);
72849c53ac9SJohnathan Mantey             }
72949c53ac9SJohnathan Mantey         }
73049c53ac9SJohnathan Mantey     }
73149c53ac9SJohnathan Mantey }
73249c53ac9SJohnathan Mantey 
73308777fb0SLewanczyk, Dawid /**
734adc4f0dbSShawn McCarney  * @brief Finds the inventory item with the specified object path.
735adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
736adc4f0dbSShawn McCarney  * @param invItemObjPath D-Bus object path of inventory item.
737adc4f0dbSShawn McCarney  * @return Inventory item within vector, or nullptr if no match found.
7388fb49dd6SShawn McCarney  */
73923a21a1cSEd Tanous inline InventoryItem* findInventoryItem(
740b5a76932SEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
741adc4f0dbSShawn McCarney     const std::string& invItemObjPath)
7428fb49dd6SShawn McCarney {
743adc4f0dbSShawn McCarney     for (InventoryItem& inventoryItem : *inventoryItems)
7448fb49dd6SShawn McCarney     {
745adc4f0dbSShawn McCarney         if (inventoryItem.objectPath == invItemObjPath)
7468fb49dd6SShawn McCarney         {
747adc4f0dbSShawn McCarney             return &inventoryItem;
7488fb49dd6SShawn McCarney         }
7498fb49dd6SShawn McCarney     }
7508fb49dd6SShawn McCarney     return nullptr;
7518fb49dd6SShawn McCarney }
7528fb49dd6SShawn McCarney 
7538fb49dd6SShawn McCarney /**
754adc4f0dbSShawn McCarney  * @brief Finds the inventory item associated with the specified sensor.
755adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
756adc4f0dbSShawn McCarney  * @param sensorObjPath D-Bus object path of sensor.
757adc4f0dbSShawn McCarney  * @return Inventory item within vector, or nullptr if no match found.
7588fb49dd6SShawn McCarney  */
75923a21a1cSEd Tanous inline InventoryItem* findInventoryItemForSensor(
760b5a76932SEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
761adc4f0dbSShawn McCarney     const std::string& sensorObjPath)
762adc4f0dbSShawn McCarney {
763adc4f0dbSShawn McCarney     for (InventoryItem& inventoryItem : *inventoryItems)
764adc4f0dbSShawn McCarney     {
765db0d36efSEd Tanous         if (inventoryItem.sensors.contains(sensorObjPath))
766adc4f0dbSShawn McCarney         {
767adc4f0dbSShawn McCarney             return &inventoryItem;
768adc4f0dbSShawn McCarney         }
769adc4f0dbSShawn McCarney     }
770adc4f0dbSShawn McCarney     return nullptr;
771adc4f0dbSShawn McCarney }
772adc4f0dbSShawn McCarney 
773adc4f0dbSShawn McCarney /**
774d500549bSAnthony Wilson  * @brief Finds the inventory item associated with the specified led path.
775d500549bSAnthony Wilson  * @param inventoryItems D-Bus inventory items associated with sensors.
776d500549bSAnthony Wilson  * @param ledObjPath D-Bus object path of led.
777d500549bSAnthony Wilson  * @return Inventory item within vector, or nullptr if no match found.
778d500549bSAnthony Wilson  */
779bd79bce8SPatrick Williams inline InventoryItem* findInventoryItemForLed(
780bd79bce8SPatrick Williams     std::vector<InventoryItem>& inventoryItems, const std::string& ledObjPath)
781d500549bSAnthony Wilson {
782d500549bSAnthony Wilson     for (InventoryItem& inventoryItem : inventoryItems)
783d500549bSAnthony Wilson     {
784d500549bSAnthony Wilson         if (inventoryItem.ledObjectPath == ledObjPath)
785d500549bSAnthony Wilson         {
786d500549bSAnthony Wilson             return &inventoryItem;
787d500549bSAnthony Wilson         }
788d500549bSAnthony Wilson     }
789d500549bSAnthony Wilson     return nullptr;
790d500549bSAnthony Wilson }
791d500549bSAnthony Wilson 
792d500549bSAnthony Wilson /**
793adc4f0dbSShawn McCarney  * @brief Adds inventory item and associated sensor to specified vector.
794adc4f0dbSShawn McCarney  *
795adc4f0dbSShawn McCarney  * Adds a new InventoryItem to the vector if necessary.  Searches for an
796adc4f0dbSShawn McCarney  * existing InventoryItem with the specified object path.  If not found, one is
797adc4f0dbSShawn McCarney  * added to the vector.
798adc4f0dbSShawn McCarney  *
799adc4f0dbSShawn McCarney  * Next, the specified sensor is added to the set of sensors associated with the
800adc4f0dbSShawn McCarney  * InventoryItem.
801adc4f0dbSShawn McCarney  *
802adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
803adc4f0dbSShawn McCarney  * @param invItemObjPath D-Bus object path of inventory item.
804adc4f0dbSShawn McCarney  * @param sensorObjPath D-Bus object path of sensor
805adc4f0dbSShawn McCarney  */
806b5a76932SEd Tanous inline void addInventoryItem(
807b5a76932SEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
808b5a76932SEd Tanous     const std::string& invItemObjPath, const std::string& sensorObjPath)
809adc4f0dbSShawn McCarney {
810adc4f0dbSShawn McCarney     // Look for inventory item in vector
811bd79bce8SPatrick Williams     InventoryItem* inventoryItem =
812bd79bce8SPatrick Williams         findInventoryItem(inventoryItems, invItemObjPath);
813adc4f0dbSShawn McCarney 
814adc4f0dbSShawn McCarney     // If inventory item doesn't exist in vector, add it
815adc4f0dbSShawn McCarney     if (inventoryItem == nullptr)
816adc4f0dbSShawn McCarney     {
817adc4f0dbSShawn McCarney         inventoryItems->emplace_back(invItemObjPath);
818adc4f0dbSShawn McCarney         inventoryItem = &(inventoryItems->back());
819adc4f0dbSShawn McCarney     }
820adc4f0dbSShawn McCarney 
821adc4f0dbSShawn McCarney     // Add sensor to set of sensors associated with inventory item
822adc4f0dbSShawn McCarney     inventoryItem->sensors.emplace(sensorObjPath);
823adc4f0dbSShawn McCarney }
824adc4f0dbSShawn McCarney 
825adc4f0dbSShawn McCarney /**
826adc4f0dbSShawn McCarney  * @brief Stores D-Bus data in the specified inventory item.
827adc4f0dbSShawn McCarney  *
828adc4f0dbSShawn McCarney  * Finds D-Bus data in the specified map of interfaces.  Stores the data in the
829adc4f0dbSShawn McCarney  * specified InventoryItem.
830adc4f0dbSShawn McCarney  *
831adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
832adc4f0dbSShawn McCarney  * response.
833adc4f0dbSShawn McCarney  *
834adc4f0dbSShawn McCarney  * @param inventoryItem Inventory item where data will be stored.
835adc4f0dbSShawn McCarney  * @param interfacesDict Map containing D-Bus interfaces and their properties
836adc4f0dbSShawn McCarney  * for the specified inventory item.
837adc4f0dbSShawn McCarney  */
83823a21a1cSEd Tanous inline void storeInventoryItemData(
839adc4f0dbSShawn McCarney     InventoryItem& inventoryItem,
84080f79a40SMichael Shen     const dbus::utility::DBusInterfacesMap& interfacesDict)
8418fb49dd6SShawn McCarney {
842adc4f0dbSShawn McCarney     // Get properties from Inventory.Item interface
843711ac7a9SEd Tanous 
8449eb808c1SEd Tanous     for (const auto& [interface, values] : interfacesDict)
8458fb49dd6SShawn McCarney     {
846711ac7a9SEd Tanous         if (interface == "xyz.openbmc_project.Inventory.Item")
8478fb49dd6SShawn McCarney         {
8489eb808c1SEd Tanous             for (const auto& [name, dbusValue] : values)
849711ac7a9SEd Tanous             {
850711ac7a9SEd Tanous                 if (name == "Present")
851711ac7a9SEd Tanous                 {
852711ac7a9SEd Tanous                     const bool* value = std::get_if<bool>(&dbusValue);
853adc4f0dbSShawn McCarney                     if (value != nullptr)
8548fb49dd6SShawn McCarney                     {
855adc4f0dbSShawn McCarney                         inventoryItem.isPresent = *value;
8568fb49dd6SShawn McCarney                     }
8578fb49dd6SShawn McCarney                 }
8588fb49dd6SShawn McCarney             }
859711ac7a9SEd Tanous         }
860adc4f0dbSShawn McCarney         // Check if Inventory.Item.PowerSupply interface is present
861711ac7a9SEd Tanous 
862711ac7a9SEd Tanous         if (interface == "xyz.openbmc_project.Inventory.Item.PowerSupply")
8638fb49dd6SShawn McCarney         {
864adc4f0dbSShawn McCarney             inventoryItem.isPowerSupply = true;
8658fb49dd6SShawn McCarney         }
866adc4f0dbSShawn McCarney 
867adc4f0dbSShawn McCarney         // Get properties from Inventory.Decorator.Asset interface
868711ac7a9SEd Tanous         if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
869adc4f0dbSShawn McCarney         {
8709eb808c1SEd Tanous             for (const auto& [name, dbusValue] : values)
871711ac7a9SEd Tanous             {
872711ac7a9SEd Tanous                 if (name == "Manufacturer")
873adc4f0dbSShawn McCarney                 {
874adc4f0dbSShawn McCarney                     const std::string* value =
875711ac7a9SEd Tanous                         std::get_if<std::string>(&dbusValue);
876adc4f0dbSShawn McCarney                     if (value != nullptr)
877adc4f0dbSShawn McCarney                     {
878adc4f0dbSShawn McCarney                         inventoryItem.manufacturer = *value;
879adc4f0dbSShawn McCarney                     }
880adc4f0dbSShawn McCarney                 }
881711ac7a9SEd Tanous                 if (name == "Model")
882adc4f0dbSShawn McCarney                 {
883adc4f0dbSShawn McCarney                     const std::string* value =
884711ac7a9SEd Tanous                         std::get_if<std::string>(&dbusValue);
885adc4f0dbSShawn McCarney                     if (value != nullptr)
886adc4f0dbSShawn McCarney                     {
887adc4f0dbSShawn McCarney                         inventoryItem.model = *value;
888adc4f0dbSShawn McCarney                     }
889adc4f0dbSShawn McCarney                 }
890711ac7a9SEd Tanous                 if (name == "SerialNumber")
891adc4f0dbSShawn McCarney                 {
892adc4f0dbSShawn McCarney                     const std::string* value =
893711ac7a9SEd Tanous                         std::get_if<std::string>(&dbusValue);
894adc4f0dbSShawn McCarney                     if (value != nullptr)
895adc4f0dbSShawn McCarney                     {
896adc4f0dbSShawn McCarney                         inventoryItem.serialNumber = *value;
897adc4f0dbSShawn McCarney                     }
898adc4f0dbSShawn McCarney                 }
899711ac7a9SEd Tanous                 if (name == "PartNumber")
900711ac7a9SEd Tanous                 {
901711ac7a9SEd Tanous                     const std::string* value =
902711ac7a9SEd Tanous                         std::get_if<std::string>(&dbusValue);
903711ac7a9SEd Tanous                     if (value != nullptr)
904711ac7a9SEd Tanous                     {
905711ac7a9SEd Tanous                         inventoryItem.partNumber = *value;
906711ac7a9SEd Tanous                     }
907711ac7a9SEd Tanous                 }
908711ac7a9SEd Tanous             }
909adc4f0dbSShawn McCarney         }
910adc4f0dbSShawn McCarney 
911711ac7a9SEd Tanous         if (interface ==
912711ac7a9SEd Tanous             "xyz.openbmc_project.State.Decorator.OperationalStatus")
913adc4f0dbSShawn McCarney         {
9149eb808c1SEd Tanous             for (const auto& [name, dbusValue] : values)
915adc4f0dbSShawn McCarney             {
916711ac7a9SEd Tanous                 if (name == "Functional")
917711ac7a9SEd Tanous                 {
918711ac7a9SEd Tanous                     const bool* value = std::get_if<bool>(&dbusValue);
919adc4f0dbSShawn McCarney                     if (value != nullptr)
920adc4f0dbSShawn McCarney                     {
921adc4f0dbSShawn McCarney                         inventoryItem.isFunctional = *value;
9228fb49dd6SShawn McCarney                     }
9238fb49dd6SShawn McCarney                 }
9248fb49dd6SShawn McCarney             }
9258fb49dd6SShawn McCarney         }
926711ac7a9SEd Tanous     }
927711ac7a9SEd Tanous }
9288fb49dd6SShawn McCarney 
9298fb49dd6SShawn McCarney /**
930adc4f0dbSShawn McCarney  * @brief Gets D-Bus data for inventory items associated with sensors.
9318fb49dd6SShawn McCarney  *
932adc4f0dbSShawn McCarney  * Uses the specified connections (services) to obtain D-Bus data for inventory
933adc4f0dbSShawn McCarney  * items associated with sensors.  Stores the resulting data in the
934adc4f0dbSShawn McCarney  * inventoryItems vector.
9358fb49dd6SShawn McCarney  *
936adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
937adc4f0dbSShawn McCarney  * response.
938adc4f0dbSShawn McCarney  *
939adc4f0dbSShawn McCarney  * Finds the inventory item data asynchronously.  Invokes callback when data has
940adc4f0dbSShawn McCarney  * been obtained.
941adc4f0dbSShawn McCarney  *
942adc4f0dbSShawn McCarney  * The callback must have the following signature:
943adc4f0dbSShawn McCarney  *   @code
944d500549bSAnthony Wilson  *   callback(void)
945adc4f0dbSShawn McCarney  *   @endcode
946adc4f0dbSShawn McCarney  *
947adc4f0dbSShawn McCarney  * This function is called recursively, obtaining data asynchronously from one
948adc4f0dbSShawn McCarney  * connection in each call.  This ensures the callback is not invoked until the
949adc4f0dbSShawn McCarney  * last asynchronous function has completed.
9508fb49dd6SShawn McCarney  *
9518fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
952adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
953adc4f0dbSShawn McCarney  * @param invConnections Connections that provide data for the inventory items.
9548fb49dd6SShawn McCarney  * implements ObjectManager.
955adc4f0dbSShawn McCarney  * @param callback Callback to invoke when inventory data has been obtained.
956adc4f0dbSShawn McCarney  * @param invConnectionsIndex Current index in invConnections.  Only specified
957adc4f0dbSShawn McCarney  * in recursive calls to this function.
9588fb49dd6SShawn McCarney  */
959adc4f0dbSShawn McCarney template <typename Callback>
9604ff0f1f4SEd Tanous void getInventoryItemsData(
961daadfb2eSEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
962daadfb2eSEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
963daadfb2eSEd Tanous     const std::shared_ptr<std::set<std::string>>& invConnections,
964daadfb2eSEd Tanous     Callback&& callback, size_t invConnectionsIndex = 0)
9658fb49dd6SShawn McCarney {
96662598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemsData enter");
9678fb49dd6SShawn McCarney 
968adc4f0dbSShawn McCarney     // If no more connections left, call callback
969adc4f0dbSShawn McCarney     if (invConnectionsIndex >= invConnections->size())
9708fb49dd6SShawn McCarney     {
971d500549bSAnthony Wilson         callback();
97262598e31SEd Tanous         BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
973adc4f0dbSShawn McCarney         return;
974adc4f0dbSShawn McCarney     }
975adc4f0dbSShawn McCarney 
976adc4f0dbSShawn McCarney     // Get inventory item data from current connection
977fe04d49cSNan Zhou     auto it = invConnections->begin();
978fe04d49cSNan Zhou     std::advance(it, invConnectionsIndex);
979adc4f0dbSShawn McCarney     if (it != invConnections->end())
980adc4f0dbSShawn McCarney     {
981adc4f0dbSShawn McCarney         const std::string& invConnection = *it;
982adc4f0dbSShawn McCarney 
9835eb468daSGeorge Liu         // Get all object paths and their interfaces for current connection
9845eb468daSGeorge Liu         sdbusplus::message::object_path path("/xyz/openbmc_project/inventory");
9855eb468daSGeorge Liu         dbus::utility::getManagedObjects(
9865eb468daSGeorge Liu             invConnection, path,
9875eb468daSGeorge Liu             [sensorsAsyncResp, inventoryItems, invConnections,
9888cb2c024SEd Tanous              callback = std::forward<Callback>(callback), invConnectionsIndex](
9895e7e2dc5SEd Tanous                 const boost::system::error_code& ec,
9904e0d8789SEd Tanous                 const dbus::utility::ManagedObjectType& resp) mutable {
99162598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler enter");
9928fb49dd6SShawn McCarney                 if (ec)
9938fb49dd6SShawn McCarney                 {
99462598e31SEd Tanous                     BMCWEB_LOG_ERROR(
99562598e31SEd Tanous                         "getInventoryItemsData respHandler DBus error {}", ec);
9968d1b46d7Szhanghch05                     messages::internalError(sensorsAsyncResp->asyncResp->res);
9978fb49dd6SShawn McCarney                     return;
9988fb49dd6SShawn McCarney                 }
9998fb49dd6SShawn McCarney 
10008fb49dd6SShawn McCarney                 // Loop through returned object paths
10018fb49dd6SShawn McCarney                 for (const auto& objDictEntry : resp)
10028fb49dd6SShawn McCarney                 {
10038fb49dd6SShawn McCarney                     const std::string& objPath =
10048fb49dd6SShawn McCarney                         static_cast<const std::string&>(objDictEntry.first);
10058fb49dd6SShawn McCarney 
1006bd79bce8SPatrick Williams                     // If this object path is one of the specified inventory
1007bd79bce8SPatrick Williams                     // items
1008bd79bce8SPatrick Williams                     InventoryItem* inventoryItem =
1009bd79bce8SPatrick Williams                         findInventoryItem(inventoryItems, objPath);
1010adc4f0dbSShawn McCarney                     if (inventoryItem != nullptr)
10118fb49dd6SShawn McCarney                     {
1012adc4f0dbSShawn McCarney                         // Store inventory data in InventoryItem
1013bd79bce8SPatrick Williams                         storeInventoryItemData(*inventoryItem,
1014bd79bce8SPatrick Williams                                                objDictEntry.second);
10158fb49dd6SShawn McCarney                     }
10168fb49dd6SShawn McCarney                 }
10178fb49dd6SShawn McCarney 
1018adc4f0dbSShawn McCarney                 // Recurse to get inventory item data from next connection
1019adc4f0dbSShawn McCarney                 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1020d0090733SEd Tanous                                       invConnections, std::move(callback),
1021d0090733SEd Tanous                                       invConnectionsIndex + 1);
1022adc4f0dbSShawn McCarney 
102362598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler exit");
10245eb468daSGeorge Liu             });
10258fb49dd6SShawn McCarney     }
10268fb49dd6SShawn McCarney 
102762598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
10288fb49dd6SShawn McCarney }
10298fb49dd6SShawn McCarney 
10308fb49dd6SShawn McCarney /**
1031adc4f0dbSShawn McCarney  * @brief Gets connections that provide D-Bus data for inventory items.
10328fb49dd6SShawn McCarney  *
1033adc4f0dbSShawn McCarney  * Gets the D-Bus connections (services) that provide data for the inventory
1034adc4f0dbSShawn McCarney  * items that are associated with sensors.
10358fb49dd6SShawn McCarney  *
10368fb49dd6SShawn McCarney  * Finds the connections asynchronously.  Invokes callback when information has
10378fb49dd6SShawn McCarney  * been obtained.
10388fb49dd6SShawn McCarney  *
10398fb49dd6SShawn McCarney  * The callback must have the following signature:
10408fb49dd6SShawn McCarney  *   @code
1041fe04d49cSNan Zhou  *   callback(std::shared_ptr<std::set<std::string>> invConnections)
10428fb49dd6SShawn McCarney  *   @endcode
10438fb49dd6SShawn McCarney  *
10448fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
1045adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
10468fb49dd6SShawn McCarney  * @param callback Callback to invoke when connections have been obtained.
10478fb49dd6SShawn McCarney  */
10488fb49dd6SShawn McCarney template <typename Callback>
10494ff0f1f4SEd Tanous void getInventoryItemsConnections(
1050b5a76932SEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1051b5a76932SEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
10528fb49dd6SShawn McCarney     Callback&& callback)
10538fb49dd6SShawn McCarney {
105462598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemsConnections enter");
10558fb49dd6SShawn McCarney 
10568fb49dd6SShawn McCarney     const std::string path = "/xyz/openbmc_project/inventory";
1057e99073f5SGeorge Liu     constexpr std::array<std::string_view, 4> interfaces = {
10588fb49dd6SShawn McCarney         "xyz.openbmc_project.Inventory.Item",
1059adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Item.PowerSupply",
1060adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Decorator.Asset",
10618fb49dd6SShawn McCarney         "xyz.openbmc_project.State.Decorator.OperationalStatus"};
10628fb49dd6SShawn McCarney 
1063e99073f5SGeorge Liu     // Make call to ObjectMapper to find all inventory items
1064e99073f5SGeorge Liu     dbus::utility::getSubTree(
1065e99073f5SGeorge Liu         path, 0, interfaces,
10668cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), sensorsAsyncResp,
1067002d39b4SEd Tanous          inventoryItems](
1068e99073f5SGeorge Liu             const boost::system::error_code& ec,
10694e0d8789SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
1070e99073f5SGeorge Liu             // Response handler for parsing output from GetSubTree
107162598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler enter");
10728fb49dd6SShawn McCarney             if (ec)
10738fb49dd6SShawn McCarney             {
10748d1b46d7Szhanghch05                 messages::internalError(sensorsAsyncResp->asyncResp->res);
107562598e31SEd Tanous                 BMCWEB_LOG_ERROR(
1076bd79bce8SPatrick Williams                     "getInventoryItemsConnections respHandler DBus error {}",
1077bd79bce8SPatrick Williams                     ec);
10788fb49dd6SShawn McCarney                 return;
10798fb49dd6SShawn McCarney             }
10808fb49dd6SShawn McCarney 
10818fb49dd6SShawn McCarney             // Make unique list of connections for desired inventory items
1082fe04d49cSNan Zhou             std::shared_ptr<std::set<std::string>> invConnections =
1083fe04d49cSNan Zhou                 std::make_shared<std::set<std::string>>();
10848fb49dd6SShawn McCarney 
10858fb49dd6SShawn McCarney             // Loop through objects from GetSubTree
1086bd79bce8SPatrick Williams             for (const std::pair<std::string,
1087bd79bce8SPatrick Williams                                  std::vector<std::pair<
1088bd79bce8SPatrick Williams                                      std::string, std::vector<std::string>>>>&
10898fb49dd6SShawn McCarney                      object : subtree)
10908fb49dd6SShawn McCarney             {
1091adc4f0dbSShawn McCarney                 // Check if object path is one of the specified inventory items
10928fb49dd6SShawn McCarney                 const std::string& objPath = object.first;
1093adc4f0dbSShawn McCarney                 if (findInventoryItem(inventoryItems, objPath) != nullptr)
10948fb49dd6SShawn McCarney                 {
10958fb49dd6SShawn McCarney                     // Store all connections to inventory item
10968fb49dd6SShawn McCarney                     for (const std::pair<std::string, std::vector<std::string>>&
10978fb49dd6SShawn McCarney                              objData : object.second)
10988fb49dd6SShawn McCarney                     {
10998fb49dd6SShawn McCarney                         const std::string& invConnection = objData.first;
11008fb49dd6SShawn McCarney                         invConnections->insert(invConnection);
11018fb49dd6SShawn McCarney                     }
11028fb49dd6SShawn McCarney                 }
11038fb49dd6SShawn McCarney             }
1104d500549bSAnthony Wilson 
11058fb49dd6SShawn McCarney             callback(invConnections);
110662598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler exit");
1107e99073f5SGeorge Liu         });
110862598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemsConnections exit");
11098fb49dd6SShawn McCarney }
11108fb49dd6SShawn McCarney 
11118fb49dd6SShawn McCarney /**
1112adc4f0dbSShawn McCarney  * @brief Gets associations from sensors to inventory items.
11138fb49dd6SShawn McCarney  *
11148fb49dd6SShawn McCarney  * Looks for ObjectMapper associations from the specified sensors to related
1115d500549bSAnthony Wilson  * inventory items. Then finds the associations from those inventory items to
1116d500549bSAnthony Wilson  * their LEDs, if any.
11178fb49dd6SShawn McCarney  *
11188fb49dd6SShawn McCarney  * Finds the inventory items asynchronously.  Invokes callback when information
11198fb49dd6SShawn McCarney  * has been obtained.
11208fb49dd6SShawn McCarney  *
11218fb49dd6SShawn McCarney  * The callback must have the following signature:
11228fb49dd6SShawn McCarney  *   @code
1123adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
11248fb49dd6SShawn McCarney  *   @endcode
11258fb49dd6SShawn McCarney  *
11268fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
11278fb49dd6SShawn McCarney  * @param sensorNames All sensors within the current chassis.
11288fb49dd6SShawn McCarney  * implements ObjectManager.
11298fb49dd6SShawn McCarney  * @param callback Callback to invoke when inventory items have been obtained.
11308fb49dd6SShawn McCarney  */
11318fb49dd6SShawn McCarney template <typename Callback>
11324ff0f1f4SEd Tanous void getInventoryItemAssociations(
1133b5a76932SEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1134fe04d49cSNan Zhou     const std::shared_ptr<std::set<std::string>>& sensorNames,
11358fb49dd6SShawn McCarney     Callback&& callback)
11368fb49dd6SShawn McCarney {
113762598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemAssociations enter");
11388fb49dd6SShawn McCarney 
11395eb468daSGeorge Liu     // Call GetManagedObjects on the ObjectMapper to get all associations
11405eb468daSGeorge Liu     sdbusplus::message::object_path path("/");
11415eb468daSGeorge Liu     dbus::utility::getManagedObjects(
11425eb468daSGeorge Liu         "xyz.openbmc_project.ObjectMapper", path,
11438cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), sensorsAsyncResp,
11445e7e2dc5SEd Tanous          sensorNames](const boost::system::error_code& ec,
11454e0d8789SEd Tanous                       const dbus::utility::ManagedObjectType& resp) mutable {
114662598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler enter");
11478fb49dd6SShawn McCarney             if (ec)
11488fb49dd6SShawn McCarney             {
114962598e31SEd Tanous                 BMCWEB_LOG_ERROR(
1150bd79bce8SPatrick Williams                     "getInventoryItemAssociations respHandler DBus error {}",
1151bd79bce8SPatrick Williams                     ec);
11528d1b46d7Szhanghch05                 messages::internalError(sensorsAsyncResp->asyncResp->res);
11538fb49dd6SShawn McCarney                 return;
11548fb49dd6SShawn McCarney             }
11558fb49dd6SShawn McCarney 
1156adc4f0dbSShawn McCarney             // Create vector to hold list of inventory items
1157adc4f0dbSShawn McCarney             std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1158adc4f0dbSShawn McCarney                 std::make_shared<std::vector<InventoryItem>>();
1159adc4f0dbSShawn McCarney 
11608fb49dd6SShawn McCarney             // Loop through returned object paths
11618fb49dd6SShawn McCarney             std::string sensorAssocPath;
11628fb49dd6SShawn McCarney             sensorAssocPath.reserve(128); // avoid memory allocations
11638fb49dd6SShawn McCarney             for (const auto& objDictEntry : resp)
11648fb49dd6SShawn McCarney             {
11658fb49dd6SShawn McCarney                 const std::string& objPath =
11668fb49dd6SShawn McCarney                     static_cast<const std::string&>(objDictEntry.first);
11678fb49dd6SShawn McCarney 
1168bd79bce8SPatrick Williams                 // If path is inventory association for one of the specified
1169bd79bce8SPatrick Williams                 // sensors
11708fb49dd6SShawn McCarney                 for (const std::string& sensorName : *sensorNames)
11718fb49dd6SShawn McCarney                 {
11728fb49dd6SShawn McCarney                     sensorAssocPath = sensorName;
11738fb49dd6SShawn McCarney                     sensorAssocPath += "/inventory";
11748fb49dd6SShawn McCarney                     if (objPath == sensorAssocPath)
11758fb49dd6SShawn McCarney                     {
11768fb49dd6SShawn McCarney                         // Get Association interface for object path
1177bd79bce8SPatrick Williams                         for (const auto& [interface, values] :
1178bd79bce8SPatrick Williams                              objDictEntry.second)
11798fb49dd6SShawn McCarney                         {
1180711ac7a9SEd Tanous                             if (interface == "xyz.openbmc_project.Association")
1181711ac7a9SEd Tanous                             {
1182711ac7a9SEd Tanous                                 for (const auto& [valueName, value] : values)
1183711ac7a9SEd Tanous                                 {
1184711ac7a9SEd Tanous                                     if (valueName == "endpoints")
11858fb49dd6SShawn McCarney                                     {
1186bd79bce8SPatrick Williams                                         const std::vector<std::string>*
1187bd79bce8SPatrick Williams                                             endpoints = std::get_if<
1188bd79bce8SPatrick Williams                                                 std::vector<std::string>>(
1189711ac7a9SEd Tanous                                                 &value);
1190711ac7a9SEd Tanous                                         if ((endpoints != nullptr) &&
1191711ac7a9SEd Tanous                                             !endpoints->empty())
11928fb49dd6SShawn McCarney                                         {
1193adc4f0dbSShawn McCarney                                             // Add inventory item to vector
1194adc4f0dbSShawn McCarney                                             const std::string& invItemPath =
1195adc4f0dbSShawn McCarney                                                 endpoints->front();
1196711ac7a9SEd Tanous                                             addInventoryItem(inventoryItems,
1197711ac7a9SEd Tanous                                                              invItemPath,
1198adc4f0dbSShawn McCarney                                                              sensorName);
11998fb49dd6SShawn McCarney                                         }
12008fb49dd6SShawn McCarney                                     }
12018fb49dd6SShawn McCarney                                 }
1202711ac7a9SEd Tanous                             }
1203711ac7a9SEd Tanous                         }
12048fb49dd6SShawn McCarney                         break;
12058fb49dd6SShawn McCarney                     }
12068fb49dd6SShawn McCarney                 }
12078fb49dd6SShawn McCarney             }
12088fb49dd6SShawn McCarney 
1209d500549bSAnthony Wilson             // Now loop through the returned object paths again, this time to
1210d500549bSAnthony Wilson             // find the leds associated with the inventory items we just found
1211d500549bSAnthony Wilson             std::string inventoryAssocPath;
1212d500549bSAnthony Wilson             inventoryAssocPath.reserve(128); // avoid memory allocations
1213d500549bSAnthony Wilson             for (const auto& objDictEntry : resp)
1214d500549bSAnthony Wilson             {
1215d500549bSAnthony Wilson                 const std::string& objPath =
1216d500549bSAnthony Wilson                     static_cast<const std::string&>(objDictEntry.first);
1217d500549bSAnthony Wilson 
1218d500549bSAnthony Wilson                 for (InventoryItem& inventoryItem : *inventoryItems)
1219d500549bSAnthony Wilson                 {
1220d500549bSAnthony Wilson                     inventoryAssocPath = inventoryItem.objectPath;
1221d500549bSAnthony Wilson                     inventoryAssocPath += "/leds";
1222d500549bSAnthony Wilson                     if (objPath == inventoryAssocPath)
1223d500549bSAnthony Wilson                     {
1224bd79bce8SPatrick Williams                         for (const auto& [interface, values] :
1225bd79bce8SPatrick Williams                              objDictEntry.second)
1226d500549bSAnthony Wilson                         {
1227711ac7a9SEd Tanous                             if (interface == "xyz.openbmc_project.Association")
1228711ac7a9SEd Tanous                             {
1229711ac7a9SEd Tanous                                 for (const auto& [valueName, value] : values)
1230711ac7a9SEd Tanous                                 {
1231711ac7a9SEd Tanous                                     if (valueName == "endpoints")
1232d500549bSAnthony Wilson                                     {
1233bd79bce8SPatrick Williams                                         const std::vector<std::string>*
1234bd79bce8SPatrick Williams                                             endpoints = std::get_if<
1235bd79bce8SPatrick Williams                                                 std::vector<std::string>>(
1236711ac7a9SEd Tanous                                                 &value);
1237711ac7a9SEd Tanous                                         if ((endpoints != nullptr) &&
1238711ac7a9SEd Tanous                                             !endpoints->empty())
1239d500549bSAnthony Wilson                                         {
1240711ac7a9SEd Tanous                                             // Add inventory item to vector
1241d500549bSAnthony Wilson                                             // Store LED path in inventory item
1242711ac7a9SEd Tanous                                             const std::string& ledPath =
1243711ac7a9SEd Tanous                                                 endpoints->front();
1244bd79bce8SPatrick Williams                                             inventoryItem.ledObjectPath =
1245bd79bce8SPatrick Williams                                                 ledPath;
1246d500549bSAnthony Wilson                                         }
1247d500549bSAnthony Wilson                                     }
1248d500549bSAnthony Wilson                                 }
1249711ac7a9SEd Tanous                             }
1250711ac7a9SEd Tanous                         }
1251711ac7a9SEd Tanous 
1252d500549bSAnthony Wilson                         break;
1253d500549bSAnthony Wilson                     }
1254d500549bSAnthony Wilson                 }
1255d500549bSAnthony Wilson             }
1256adc4f0dbSShawn McCarney             callback(inventoryItems);
125762598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler exit");
12585eb468daSGeorge Liu         });
12598fb49dd6SShawn McCarney 
126062598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemAssociations exit");
12618fb49dd6SShawn McCarney }
12628fb49dd6SShawn McCarney 
12638fb49dd6SShawn McCarney /**
1264d500549bSAnthony Wilson  * @brief Gets D-Bus data for inventory item leds associated with sensors.
1265d500549bSAnthony Wilson  *
1266d500549bSAnthony Wilson  * Uses the specified connections (services) to obtain D-Bus data for inventory
1267d500549bSAnthony Wilson  * item leds associated with sensors.  Stores the resulting data in the
1268d500549bSAnthony Wilson  * inventoryItems vector.
1269d500549bSAnthony Wilson  *
1270d500549bSAnthony Wilson  * This data is later used to provide sensor property values in the JSON
1271d500549bSAnthony Wilson  * response.
1272d500549bSAnthony Wilson  *
1273d500549bSAnthony Wilson  * Finds the inventory item led data asynchronously.  Invokes callback when data
1274d500549bSAnthony Wilson  * has been obtained.
1275d500549bSAnthony Wilson  *
1276d500549bSAnthony Wilson  * The callback must have the following signature:
1277d500549bSAnthony Wilson  *   @code
127842cbe538SGunnar Mills  *   callback()
1279d500549bSAnthony Wilson  *   @endcode
1280d500549bSAnthony Wilson  *
1281d500549bSAnthony Wilson  * This function is called recursively, obtaining data asynchronously from one
1282d500549bSAnthony Wilson  * connection in each call.  This ensures the callback is not invoked until the
1283d500549bSAnthony Wilson  * last asynchronous function has completed.
1284d500549bSAnthony Wilson  *
1285d500549bSAnthony Wilson  * @param sensorsAsyncResp Pointer to object holding response data.
1286d500549bSAnthony Wilson  * @param inventoryItems D-Bus inventory items associated with sensors.
1287d500549bSAnthony Wilson  * @param ledConnections Connections that provide data for the inventory leds.
1288d500549bSAnthony Wilson  * @param callback Callback to invoke when inventory data has been obtained.
1289d500549bSAnthony Wilson  * @param ledConnectionsIndex Current index in ledConnections.  Only specified
1290d500549bSAnthony Wilson  * in recursive calls to this function.
1291d500549bSAnthony Wilson  */
1292d500549bSAnthony Wilson template <typename Callback>
1293d500549bSAnthony Wilson void getInventoryLedData(
1294daadfb2eSEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1295daadfb2eSEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
1296daadfb2eSEd Tanous     const std::shared_ptr<std::map<std::string, std::string>>& ledConnections,
1297d500549bSAnthony Wilson     Callback&& callback, size_t ledConnectionsIndex = 0)
1298d500549bSAnthony Wilson {
129962598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryLedData enter");
1300d500549bSAnthony Wilson 
1301d500549bSAnthony Wilson     // If no more connections left, call callback
1302d500549bSAnthony Wilson     if (ledConnectionsIndex >= ledConnections->size())
1303d500549bSAnthony Wilson     {
130442cbe538SGunnar Mills         callback();
130562598e31SEd Tanous         BMCWEB_LOG_DEBUG("getInventoryLedData exit");
1306d500549bSAnthony Wilson         return;
1307d500549bSAnthony Wilson     }
1308d500549bSAnthony Wilson 
1309d500549bSAnthony Wilson     // Get inventory item data from current connection
1310fe04d49cSNan Zhou     auto it = ledConnections->begin();
1311fe04d49cSNan Zhou     std::advance(it, ledConnectionsIndex);
1312d500549bSAnthony Wilson     if (it != ledConnections->end())
1313d500549bSAnthony Wilson     {
1314d500549bSAnthony Wilson         const std::string& ledPath = (*it).first;
1315d500549bSAnthony Wilson         const std::string& ledConnection = (*it).second;
1316d500549bSAnthony Wilson         // Response handler for Get State property
13171e1e598dSJonathan Doman         auto respHandler =
13181e1e598dSJonathan Doman             [sensorsAsyncResp, inventoryItems, ledConnections, ledPath,
13194e0d8789SEd Tanous              callback = std::forward<Callback>(callback),
13204e0d8789SEd Tanous              ledConnectionsIndex](const boost::system::error_code& ec,
13214e0d8789SEd Tanous                                   const std::string& state) mutable {
132262598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler enter");
1323d500549bSAnthony Wilson                 if (ec)
1324d500549bSAnthony Wilson                 {
132562598e31SEd Tanous                     BMCWEB_LOG_ERROR(
132662598e31SEd Tanous                         "getInventoryLedData respHandler DBus error {}", ec);
13278d1b46d7Szhanghch05                     messages::internalError(sensorsAsyncResp->asyncResp->res);
1328d500549bSAnthony Wilson                     return;
1329d500549bSAnthony Wilson                 }
1330d500549bSAnthony Wilson 
133162598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Led state: {}", state);
1332d500549bSAnthony Wilson                 // Find inventory item with this LED object path
1333d500549bSAnthony Wilson                 InventoryItem* inventoryItem =
1334d500549bSAnthony Wilson                     findInventoryItemForLed(*inventoryItems, ledPath);
1335d500549bSAnthony Wilson                 if (inventoryItem != nullptr)
1336d500549bSAnthony Wilson                 {
1337d500549bSAnthony Wilson                     // Store LED state in InventoryItem
133811ba3979SEd Tanous                     if (state.ends_with("On"))
1339d500549bSAnthony Wilson                     {
1340c9563608SJanet Adkins                         inventoryItem->ledState = sensor_utils::LedState::ON;
1341d500549bSAnthony Wilson                     }
134211ba3979SEd Tanous                     else if (state.ends_with("Blink"))
1343d500549bSAnthony Wilson                     {
1344c9563608SJanet Adkins                         inventoryItem->ledState = sensor_utils::LedState::BLINK;
1345d500549bSAnthony Wilson                     }
134611ba3979SEd Tanous                     else if (state.ends_with("Off"))
1347d500549bSAnthony Wilson                     {
1348c9563608SJanet Adkins                         inventoryItem->ledState = sensor_utils::LedState::OFF;
1349d500549bSAnthony Wilson                     }
1350d500549bSAnthony Wilson                     else
1351d500549bSAnthony Wilson                     {
1352c9563608SJanet Adkins                         inventoryItem->ledState =
1353c9563608SJanet Adkins                             sensor_utils::LedState::UNKNOWN;
1354d500549bSAnthony Wilson                     }
1355d500549bSAnthony Wilson                 }
1356d500549bSAnthony Wilson 
1357d500549bSAnthony Wilson                 // Recurse to get LED data from next connection
1358d500549bSAnthony Wilson                 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1359d500549bSAnthony Wilson                                     ledConnections, std::move(callback),
1360d500549bSAnthony Wilson                                     ledConnectionsIndex + 1);
1361d500549bSAnthony Wilson 
136262598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler exit");
1363d500549bSAnthony Wilson             };
1364d500549bSAnthony Wilson 
1365d500549bSAnthony Wilson         // Get the State property for the current LED
1366deae6a78SEd Tanous         dbus::utility::getProperty<std::string>(
1367deae6a78SEd Tanous             ledConnection, ledPath, "xyz.openbmc_project.Led.Physical", "State",
13681e1e598dSJonathan Doman             std::move(respHandler));
1369d500549bSAnthony Wilson     }
1370d500549bSAnthony Wilson 
137162598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryLedData exit");
1372d500549bSAnthony Wilson }
1373d500549bSAnthony Wilson 
1374d500549bSAnthony Wilson /**
1375d500549bSAnthony Wilson  * @brief Gets LED data for LEDs associated with given inventory items.
1376d500549bSAnthony Wilson  *
1377d500549bSAnthony Wilson  * Gets the D-Bus connections (services) that provide LED data for the LEDs
1378d500549bSAnthony Wilson  * associated with the specified inventory items.  Then gets the LED data from
1379d500549bSAnthony Wilson  * each connection and stores it in the inventory item.
1380d500549bSAnthony Wilson  *
1381d500549bSAnthony Wilson  * This data is later used to provide sensor property values in the JSON
1382d500549bSAnthony Wilson  * response.
1383d500549bSAnthony Wilson  *
1384d500549bSAnthony Wilson  * Finds the LED data asynchronously.  Invokes callback when information has
1385d500549bSAnthony Wilson  * been obtained.
1386d500549bSAnthony Wilson  *
1387d500549bSAnthony Wilson  * The callback must have the following signature:
1388d500549bSAnthony Wilson  *   @code
138942cbe538SGunnar Mills  *   callback()
1390d500549bSAnthony Wilson  *   @endcode
1391d500549bSAnthony Wilson  *
1392d500549bSAnthony Wilson  * @param sensorsAsyncResp Pointer to object holding response data.
1393d500549bSAnthony Wilson  * @param inventoryItems D-Bus inventory items associated with sensors.
1394d500549bSAnthony Wilson  * @param callback Callback to invoke when inventory items have been obtained.
1395d500549bSAnthony Wilson  */
1396d500549bSAnthony Wilson template <typename Callback>
1397d500549bSAnthony Wilson void getInventoryLeds(
1398daadfb2eSEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1399daadfb2eSEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
1400d500549bSAnthony Wilson     Callback&& callback)
1401d500549bSAnthony Wilson {
140262598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryLeds enter");
1403d500549bSAnthony Wilson 
1404d500549bSAnthony Wilson     const std::string path = "/xyz/openbmc_project";
1405e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
1406d500549bSAnthony Wilson         "xyz.openbmc_project.Led.Physical"};
1407d500549bSAnthony Wilson 
1408e99073f5SGeorge Liu     // Make call to ObjectMapper to find all inventory items
1409e99073f5SGeorge Liu     dbus::utility::getSubTree(
1410e99073f5SGeorge Liu         path, 0, interfaces,
14118cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), sensorsAsyncResp,
1412002d39b4SEd Tanous          inventoryItems](
1413e99073f5SGeorge Liu             const boost::system::error_code& ec,
14144e0d8789SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
1415e99073f5SGeorge Liu             // Response handler for parsing output from GetSubTree
141662598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryLeds respHandler enter");
1417d500549bSAnthony Wilson             if (ec)
1418d500549bSAnthony Wilson             {
14198d1b46d7Szhanghch05                 messages::internalError(sensorsAsyncResp->asyncResp->res);
1420bd79bce8SPatrick Williams                 BMCWEB_LOG_ERROR("getInventoryLeds respHandler DBus error {}",
1421bd79bce8SPatrick Williams                                  ec);
1422d500549bSAnthony Wilson                 return;
1423d500549bSAnthony Wilson             }
1424d500549bSAnthony Wilson 
1425d500549bSAnthony Wilson             // Build map of LED object paths to connections
1426fe04d49cSNan Zhou             std::shared_ptr<std::map<std::string, std::string>> ledConnections =
1427fe04d49cSNan Zhou                 std::make_shared<std::map<std::string, std::string>>();
1428d500549bSAnthony Wilson 
1429d500549bSAnthony Wilson             // Loop through objects from GetSubTree
1430bd79bce8SPatrick Williams             for (const std::pair<std::string,
1431bd79bce8SPatrick Williams                                  std::vector<std::pair<
1432bd79bce8SPatrick Williams                                      std::string, std::vector<std::string>>>>&
1433d500549bSAnthony Wilson                      object : subtree)
1434d500549bSAnthony Wilson             {
1435bd79bce8SPatrick Williams                 // Check if object path is LED for one of the specified
1436bd79bce8SPatrick Williams                 // inventory items
1437d500549bSAnthony Wilson                 const std::string& ledPath = object.first;
1438bd79bce8SPatrick Williams                 if (findInventoryItemForLed(*inventoryItems, ledPath) !=
1439bd79bce8SPatrick Williams                     nullptr)
1440d500549bSAnthony Wilson                 {
1441d500549bSAnthony Wilson                     // Add mapping from ledPath to connection
1442bd79bce8SPatrick Williams                     const std::string& connection =
1443bd79bce8SPatrick Williams                         object.second.begin()->first;
1444d500549bSAnthony Wilson                     (*ledConnections)[ledPath] = connection;
1445bd79bce8SPatrick Williams                     BMCWEB_LOG_DEBUG("Added mapping {} -> {}", ledPath,
1446bd79bce8SPatrick Williams                                      connection);
1447d500549bSAnthony Wilson                 }
1448d500549bSAnthony Wilson             }
1449d500549bSAnthony Wilson 
1450bd79bce8SPatrick Williams             getInventoryLedData(sensorsAsyncResp, inventoryItems,
1451bd79bce8SPatrick Williams                                 ledConnections, std::move(callback));
145262598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryLeds respHandler exit");
1453e99073f5SGeorge Liu         });
145462598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryLeds exit");
1455d500549bSAnthony Wilson }
1456d500549bSAnthony Wilson 
1457d500549bSAnthony Wilson /**
145842cbe538SGunnar Mills  * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent
145942cbe538SGunnar Mills  *
146042cbe538SGunnar Mills  * Uses the specified connections (services) (currently assumes just one) to
146142cbe538SGunnar Mills  * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in
146242cbe538SGunnar Mills  * the inventoryItems vector. Only stores data in Power Supply inventoryItems.
146342cbe538SGunnar Mills  *
146442cbe538SGunnar Mills  * This data is later used to provide sensor property values in the JSON
146542cbe538SGunnar Mills  * response.
146642cbe538SGunnar Mills  *
146742cbe538SGunnar Mills  * Finds the Power Supply Attributes data asynchronously.  Invokes callback
146842cbe538SGunnar Mills  * when data has been obtained.
146942cbe538SGunnar Mills  *
147042cbe538SGunnar Mills  * The callback must have the following signature:
147142cbe538SGunnar Mills  *   @code
147242cbe538SGunnar Mills  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
147342cbe538SGunnar Mills  *   @endcode
147442cbe538SGunnar Mills  *
147542cbe538SGunnar Mills  * @param sensorsAsyncResp Pointer to object holding response data.
147642cbe538SGunnar Mills  * @param inventoryItems D-Bus inventory items associated with sensors.
147742cbe538SGunnar Mills  * @param psAttributesConnections Connections that provide data for the Power
147842cbe538SGunnar Mills  *        Supply Attributes
147942cbe538SGunnar Mills  * @param callback Callback to invoke when data has been obtained.
148042cbe538SGunnar Mills  */
148142cbe538SGunnar Mills template <typename Callback>
148242cbe538SGunnar Mills void getPowerSupplyAttributesData(
1483b5a76932SEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1484daadfb2eSEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
1485fe04d49cSNan Zhou     const std::map<std::string, std::string>& psAttributesConnections,
148642cbe538SGunnar Mills     Callback&& callback)
148742cbe538SGunnar Mills {
148862598e31SEd Tanous     BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData enter");
148942cbe538SGunnar Mills 
149042cbe538SGunnar Mills     if (psAttributesConnections.empty())
149142cbe538SGunnar Mills     {
149262598e31SEd Tanous         BMCWEB_LOG_DEBUG("Can't find PowerSupplyAttributes, no connections!");
149342cbe538SGunnar Mills         callback(inventoryItems);
149442cbe538SGunnar Mills         return;
149542cbe538SGunnar Mills     }
149642cbe538SGunnar Mills 
149742cbe538SGunnar Mills     // Assuming just one connection (service) for now
1498fe04d49cSNan Zhou     auto it = psAttributesConnections.begin();
149942cbe538SGunnar Mills 
150042cbe538SGunnar Mills     const std::string& psAttributesPath = (*it).first;
150142cbe538SGunnar Mills     const std::string& psAttributesConnection = (*it).second;
150242cbe538SGunnar Mills 
150342cbe538SGunnar Mills     // Response handler for Get DeratingFactor property
15045a39f77aSPatrick Williams     auto respHandler = [sensorsAsyncResp, inventoryItems,
15058cb2c024SEd Tanous                         callback = std::forward<Callback>(callback)](
15065a39f77aSPatrick Williams                            const boost::system::error_code& ec,
15074e0d8789SEd Tanous                            uint32_t value) mutable {
150862598e31SEd Tanous         BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler enter");
150942cbe538SGunnar Mills         if (ec)
151042cbe538SGunnar Mills         {
151162598e31SEd Tanous             BMCWEB_LOG_ERROR(
151262598e31SEd Tanous                 "getPowerSupplyAttributesData respHandler DBus error {}", ec);
15138d1b46d7Szhanghch05             messages::internalError(sensorsAsyncResp->asyncResp->res);
151442cbe538SGunnar Mills             return;
151542cbe538SGunnar Mills         }
151642cbe538SGunnar Mills 
151762598e31SEd Tanous         BMCWEB_LOG_DEBUG("PS EfficiencyPercent value: {}", value);
151842cbe538SGunnar Mills         // Store value in Power Supply Inventory Items
151942cbe538SGunnar Mills         for (InventoryItem& inventoryItem : *inventoryItems)
152042cbe538SGunnar Mills         {
152155f79e6fSEd Tanous             if (inventoryItem.isPowerSupply)
152242cbe538SGunnar Mills             {
152342cbe538SGunnar Mills                 inventoryItem.powerSupplyEfficiencyPercent =
15241e1e598dSJonathan Doman                     static_cast<int>(value);
152542cbe538SGunnar Mills             }
152642cbe538SGunnar Mills         }
152742cbe538SGunnar Mills 
152862598e31SEd Tanous         BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler exit");
152942cbe538SGunnar Mills         callback(inventoryItems);
153042cbe538SGunnar Mills     };
153142cbe538SGunnar Mills 
153242cbe538SGunnar Mills     // Get the DeratingFactor property for the PowerSupplyAttributes
153342cbe538SGunnar Mills     // Currently only property on the interface/only one we care about
1534deae6a78SEd Tanous     dbus::utility::getProperty<uint32_t>(
1535deae6a78SEd Tanous         psAttributesConnection, psAttributesPath,
15361e1e598dSJonathan Doman         "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
15371e1e598dSJonathan Doman         std::move(respHandler));
153842cbe538SGunnar Mills 
153962598e31SEd Tanous     BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData exit");
154042cbe538SGunnar Mills }
154142cbe538SGunnar Mills 
154242cbe538SGunnar Mills /**
154342cbe538SGunnar Mills  * @brief Gets the Power Supply Attributes such as EfficiencyPercent
154442cbe538SGunnar Mills  *
154542cbe538SGunnar Mills  * Gets the D-Bus connection (service) that provides Power Supply Attributes
154642cbe538SGunnar Mills  * data. Then gets the Power Supply Attributes data from the connection
154742cbe538SGunnar Mills  * (currently just assumes 1 connection) and stores the data in the inventory
154842cbe538SGunnar Mills  * item.
154942cbe538SGunnar Mills  *
155042cbe538SGunnar Mills  * This data is later used to provide sensor property values in the JSON
155142cbe538SGunnar Mills  * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish.
155242cbe538SGunnar Mills  *
155342cbe538SGunnar Mills  * Finds the Power Supply Attributes data asynchronously. Invokes callback
155442cbe538SGunnar Mills  * when information has been obtained.
155542cbe538SGunnar Mills  *
155642cbe538SGunnar Mills  * The callback must have the following signature:
155742cbe538SGunnar Mills  *   @code
155842cbe538SGunnar Mills  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
155942cbe538SGunnar Mills  *   @endcode
156042cbe538SGunnar Mills  *
156142cbe538SGunnar Mills  * @param sensorsAsyncResp Pointer to object holding response data.
156242cbe538SGunnar Mills  * @param inventoryItems D-Bus inventory items associated with sensors.
156342cbe538SGunnar Mills  * @param callback Callback to invoke when data has been obtained.
156442cbe538SGunnar Mills  */
156542cbe538SGunnar Mills template <typename Callback>
156642cbe538SGunnar Mills void getPowerSupplyAttributes(
1567daadfb2eSEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1568daadfb2eSEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
156942cbe538SGunnar Mills     Callback&& callback)
157042cbe538SGunnar Mills {
157162598e31SEd Tanous     BMCWEB_LOG_DEBUG("getPowerSupplyAttributes enter");
157242cbe538SGunnar Mills 
157342cbe538SGunnar Mills     // Only need the power supply attributes when the Power Schema
15740c728b42SJanet Adkins     if (sensorsAsyncResp->chassisSubNode != sensors::powerNodeStr)
157542cbe538SGunnar Mills     {
157662598e31SEd Tanous         BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit since not Power");
157742cbe538SGunnar Mills         callback(inventoryItems);
157842cbe538SGunnar Mills         return;
157942cbe538SGunnar Mills     }
158042cbe538SGunnar Mills 
1581e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
158242cbe538SGunnar Mills         "xyz.openbmc_project.Control.PowerSupplyAttributes"};
158342cbe538SGunnar Mills 
1584e99073f5SGeorge Liu     // Make call to ObjectMapper to find the PowerSupplyAttributes service
1585e99073f5SGeorge Liu     dbus::utility::getSubTree(
1586e99073f5SGeorge Liu         "/xyz/openbmc_project", 0, interfaces,
15878cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), sensorsAsyncResp,
1588b9d36b47SEd Tanous          inventoryItems](
1589e99073f5SGeorge Liu             const boost::system::error_code& ec,
15904e0d8789SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
1591e99073f5SGeorge Liu             // Response handler for parsing output from GetSubTree
159262598e31SEd Tanous             BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler enter");
159342cbe538SGunnar Mills             if (ec)
159442cbe538SGunnar Mills             {
15958d1b46d7Szhanghch05                 messages::internalError(sensorsAsyncResp->asyncResp->res);
159662598e31SEd Tanous                 BMCWEB_LOG_ERROR(
159762598e31SEd Tanous                     "getPowerSupplyAttributes respHandler DBus error {}", ec);
159842cbe538SGunnar Mills                 return;
159942cbe538SGunnar Mills             }
160026f6976fSEd Tanous             if (subtree.empty())
160142cbe538SGunnar Mills             {
160262598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
160342cbe538SGunnar Mills                 callback(inventoryItems);
160442cbe538SGunnar Mills                 return;
160542cbe538SGunnar Mills             }
160642cbe538SGunnar Mills 
160742cbe538SGunnar Mills             // Currently we only support 1 power supply attribute, use this for
160842cbe538SGunnar Mills             // all the power supplies. Build map of object path to connection.
160942cbe538SGunnar Mills             // Assume just 1 connection and 1 path for now.
1610fe04d49cSNan Zhou             std::map<std::string, std::string> psAttributesConnections;
161142cbe538SGunnar Mills 
161242cbe538SGunnar Mills             if (subtree[0].first.empty() || subtree[0].second.empty())
161342cbe538SGunnar Mills             {
161462598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
161542cbe538SGunnar Mills                 callback(inventoryItems);
161642cbe538SGunnar Mills                 return;
161742cbe538SGunnar Mills             }
161842cbe538SGunnar Mills 
161942cbe538SGunnar Mills             const std::string& psAttributesPath = subtree[0].first;
162042cbe538SGunnar Mills             const std::string& connection = subtree[0].second.begin()->first;
162142cbe538SGunnar Mills 
162242cbe538SGunnar Mills             if (connection.empty())
162342cbe538SGunnar Mills             {
162462598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
162542cbe538SGunnar Mills                 callback(inventoryItems);
162642cbe538SGunnar Mills                 return;
162742cbe538SGunnar Mills             }
162842cbe538SGunnar Mills 
162942cbe538SGunnar Mills             psAttributesConnections[psAttributesPath] = connection;
163062598e31SEd Tanous             BMCWEB_LOG_DEBUG("Added mapping {} -> {}", psAttributesPath,
163162598e31SEd Tanous                              connection);
163242cbe538SGunnar Mills 
163342cbe538SGunnar Mills             getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems,
163442cbe538SGunnar Mills                                          psAttributesConnections,
163542cbe538SGunnar Mills                                          std::move(callback));
163662598e31SEd Tanous             BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler exit");
1637e99073f5SGeorge Liu         });
163862598e31SEd Tanous     BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit");
163942cbe538SGunnar Mills }
164042cbe538SGunnar Mills 
164142cbe538SGunnar Mills /**
1642adc4f0dbSShawn McCarney  * @brief Gets inventory items associated with sensors.
16438fb49dd6SShawn McCarney  *
16448fb49dd6SShawn McCarney  * Finds the inventory items that are associated with the specified sensors.
1645adc4f0dbSShawn McCarney  * Then gets D-Bus data for the inventory items, such as presence and VPD.
16468fb49dd6SShawn McCarney  *
1647adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
1648adc4f0dbSShawn McCarney  * response.
16498fb49dd6SShawn McCarney  *
1650adc4f0dbSShawn McCarney  * Finds the inventory items asynchronously.  Invokes callback when the
1651adc4f0dbSShawn McCarney  * inventory items have been obtained.
1652adc4f0dbSShawn McCarney  *
1653adc4f0dbSShawn McCarney  * The callback must have the following signature:
1654adc4f0dbSShawn McCarney  *   @code
1655adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1656adc4f0dbSShawn McCarney  *   @endcode
16578fb49dd6SShawn McCarney  *
16588fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
16598fb49dd6SShawn McCarney  * @param sensorNames All sensors within the current chassis.
16608fb49dd6SShawn McCarney  * implements ObjectManager.
1661adc4f0dbSShawn McCarney  * @param callback Callback to invoke when inventory items have been obtained.
16628fb49dd6SShawn McCarney  */
1663adc4f0dbSShawn McCarney template <typename Callback>
16644ff0f1f4SEd Tanous inline void
1665daadfb2eSEd Tanous     getInventoryItems(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1666daadfb2eSEd Tanous                       const std::shared_ptr<std::set<std::string>>& sensorNames,
1667adc4f0dbSShawn McCarney                       Callback&& callback)
16688fb49dd6SShawn McCarney {
166962598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItems enter");
1670adc4f0dbSShawn McCarney     auto getInventoryItemAssociationsCb =
16718cb2c024SEd Tanous         [sensorsAsyncResp, callback = std::forward<Callback>(callback)](
1672daadfb2eSEd Tanous             const std::shared_ptr<std::vector<InventoryItem>>&
16734e0d8789SEd Tanous                 inventoryItems) mutable {
167462598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb enter");
16758fb49dd6SShawn McCarney             auto getInventoryItemsConnectionsCb =
1676d0090733SEd Tanous                 [sensorsAsyncResp, inventoryItems,
16774e0d8789SEd Tanous                  callback = std::forward<Callback>(callback)](
1678daadfb2eSEd Tanous                     const std::shared_ptr<std::set<std::string>>&
16794e0d8789SEd Tanous                         invConnections) mutable {
168062598e31SEd Tanous                     BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb enter");
1681bd79bce8SPatrick Williams                     auto getInventoryItemsDataCb =
1682bd79bce8SPatrick Williams                         [sensorsAsyncResp, inventoryItems,
16834e0d8789SEd Tanous                          callback =
16844e0d8789SEd Tanous                              std::forward<Callback>(callback)]() mutable {
168562598e31SEd Tanous                             BMCWEB_LOG_DEBUG("getInventoryItemsDataCb enter");
168642cbe538SGunnar Mills 
1687bd79bce8SPatrick Williams                             auto getInventoryLedsCb =
1688bd79bce8SPatrick Williams                                 [sensorsAsyncResp, inventoryItems,
16894e0d8789SEd Tanous                                  callback = std::forward<Callback>(
16904e0d8789SEd Tanous                                      callback)]() mutable {
1691bd79bce8SPatrick Williams                                     BMCWEB_LOG_DEBUG(
1692bd79bce8SPatrick Williams                                         "getInventoryLedsCb enter");
1693bd79bce8SPatrick Williams                                     // Find Power Supply Attributes and get the
1694bd79bce8SPatrick Williams                                     // data
1695bd79bce8SPatrick Williams                                     getPowerSupplyAttributes(
1696bd79bce8SPatrick Williams                                         sensorsAsyncResp, inventoryItems,
169742cbe538SGunnar Mills                                         std::move(callback));
169862598e31SEd Tanous                                     BMCWEB_LOG_DEBUG("getInventoryLedsCb exit");
169942cbe538SGunnar Mills                                 };
170042cbe538SGunnar Mills 
1701d500549bSAnthony Wilson                             // Find led connections and get the data
1702d500549bSAnthony Wilson                             getInventoryLeds(sensorsAsyncResp, inventoryItems,
170342cbe538SGunnar Mills                                              std::move(getInventoryLedsCb));
170462598e31SEd Tanous                             BMCWEB_LOG_DEBUG("getInventoryItemsDataCb exit");
1705d500549bSAnthony Wilson                         };
17068fb49dd6SShawn McCarney 
1707adc4f0dbSShawn McCarney                     // Get inventory item data from connections
1708adc4f0dbSShawn McCarney                     getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1709d0090733SEd Tanous                                           invConnections,
1710d500549bSAnthony Wilson                                           std::move(getInventoryItemsDataCb));
171162598e31SEd Tanous                     BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb exit");
17128fb49dd6SShawn McCarney                 };
17138fb49dd6SShawn McCarney 
1714adc4f0dbSShawn McCarney             // Get connections that provide inventory item data
1715bd79bce8SPatrick Williams             getInventoryItemsConnections(
1716bd79bce8SPatrick Williams                 sensorsAsyncResp, inventoryItems,
17178fb49dd6SShawn McCarney                 std::move(getInventoryItemsConnectionsCb));
171862598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb exit");
17198fb49dd6SShawn McCarney         };
17208fb49dd6SShawn McCarney 
1721adc4f0dbSShawn McCarney     // Get associations from sensors to inventory items
1722d0090733SEd Tanous     getInventoryItemAssociations(sensorsAsyncResp, sensorNames,
1723adc4f0dbSShawn McCarney                                  std::move(getInventoryItemAssociationsCb));
172462598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItems exit");
1725adc4f0dbSShawn McCarney }
1726adc4f0dbSShawn McCarney 
1727adc4f0dbSShawn McCarney /**
1728adc4f0dbSShawn McCarney  * @brief Returns JSON PowerSupply object for the specified inventory item.
1729adc4f0dbSShawn McCarney  *
1730adc4f0dbSShawn McCarney  * Searches for a JSON PowerSupply object that matches the specified inventory
1731adc4f0dbSShawn McCarney  * item.  If one is not found, a new PowerSupply object is added to the JSON
1732adc4f0dbSShawn McCarney  * array.
1733adc4f0dbSShawn McCarney  *
1734adc4f0dbSShawn McCarney  * Multiple sensors are often associated with one power supply inventory item.
1735adc4f0dbSShawn McCarney  * As a result, multiple sensor values are stored in one JSON PowerSupply
1736adc4f0dbSShawn McCarney  * object.
1737adc4f0dbSShawn McCarney  *
1738adc4f0dbSShawn McCarney  * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1739adc4f0dbSShawn McCarney  * @param inventoryItem Inventory item for the power supply.
1740adc4f0dbSShawn McCarney  * @param chassisId Chassis that contains the power supply.
1741adc4f0dbSShawn McCarney  * @return JSON PowerSupply object for the specified inventory item.
1742adc4f0dbSShawn McCarney  */
174323a21a1cSEd Tanous inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
1744adc4f0dbSShawn McCarney                                       const InventoryItem& inventoryItem,
1745adc4f0dbSShawn McCarney                                       const std::string& chassisId)
1746adc4f0dbSShawn McCarney {
174718f8f608SEd Tanous     std::string nameS;
17486f4bd290SAlexander Hansen     nameS.resize(inventoryItem.name.size());
174918f8f608SEd Tanous     std::ranges::replace_copy(inventoryItem.name, nameS.begin(), '_', ' ');
1750adc4f0dbSShawn McCarney     // Check if matching PowerSupply object already exists in JSON array
1751adc4f0dbSShawn McCarney     for (nlohmann::json& powerSupply : powerSupplyArray)
1752adc4f0dbSShawn McCarney     {
175318f8f608SEd Tanous         nlohmann::json::iterator nameIt = powerSupply.find("Name");
175418f8f608SEd Tanous         if (nameIt == powerSupply.end())
175518f8f608SEd Tanous         {
175618f8f608SEd Tanous             continue;
175718f8f608SEd Tanous         }
175818f8f608SEd Tanous         const std::string* name = nameIt->get_ptr<std::string*>();
175918f8f608SEd Tanous         if (name == nullptr)
176018f8f608SEd Tanous         {
176118f8f608SEd Tanous             continue;
176218f8f608SEd Tanous         }
176318f8f608SEd Tanous         if (nameS == *name)
1764adc4f0dbSShawn McCarney         {
1765adc4f0dbSShawn McCarney             return powerSupply;
1766adc4f0dbSShawn McCarney         }
1767adc4f0dbSShawn McCarney     }
1768adc4f0dbSShawn McCarney 
1769adc4f0dbSShawn McCarney     // Add new PowerSupply object to JSON array
1770adc4f0dbSShawn McCarney     powerSupplyArray.push_back({});
1771adc4f0dbSShawn McCarney     nlohmann::json& powerSupply = powerSupplyArray.back();
1772bd79bce8SPatrick Williams     boost::urls::url url =
1773bd79bce8SPatrick Williams         boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
1774eddfc437SWilly Tu     url.set_fragment(("/PowerSupplies"_json_pointer).to_string());
1775eddfc437SWilly Tu     powerSupply["@odata.id"] = std::move(url);
177618f8f608SEd Tanous     std::string escaped;
17776f4bd290SAlexander Hansen     escaped.resize(inventoryItem.name.size());
177818f8f608SEd Tanous     std::ranges::replace_copy(inventoryItem.name, escaped.begin(), '_', ' ');
177918f8f608SEd Tanous     powerSupply["Name"] = std::move(escaped);
1780adc4f0dbSShawn McCarney     powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1781adc4f0dbSShawn McCarney     powerSupply["Model"] = inventoryItem.model;
1782adc4f0dbSShawn McCarney     powerSupply["PartNumber"] = inventoryItem.partNumber;
1783adc4f0dbSShawn McCarney     powerSupply["SerialNumber"] = inventoryItem.serialNumber;
1784c9563608SJanet Adkins     sensor_utils::setLedState(powerSupply, &inventoryItem);
1785adc4f0dbSShawn McCarney 
178642cbe538SGunnar Mills     if (inventoryItem.powerSupplyEfficiencyPercent >= 0)
178742cbe538SGunnar Mills     {
178842cbe538SGunnar Mills         powerSupply["EfficiencyPercent"] =
178942cbe538SGunnar Mills             inventoryItem.powerSupplyEfficiencyPercent;
179042cbe538SGunnar Mills     }
179142cbe538SGunnar Mills 
1792c9563608SJanet Adkins     powerSupply["Status"]["State"] =
1793c9563608SJanet Adkins         sensor_utils::getState(&inventoryItem, true);
1794adc4f0dbSShawn McCarney     const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1795adc4f0dbSShawn McCarney     powerSupply["Status"]["Health"] = health;
1796adc4f0dbSShawn McCarney 
1797adc4f0dbSShawn McCarney     return powerSupply;
17988fb49dd6SShawn McCarney }
17998fb49dd6SShawn McCarney 
18008fb49dd6SShawn McCarney /**
1801de629b6eSShawn McCarney  * @brief Gets the values of the specified sensors.
1802de629b6eSShawn McCarney  *
1803de629b6eSShawn McCarney  * Stores the results as JSON in the SensorsAsyncResp.
1804de629b6eSShawn McCarney  *
1805de629b6eSShawn McCarney  * Gets the sensor values asynchronously.  Stores the results later when the
1806de629b6eSShawn McCarney  * information has been obtained.
1807de629b6eSShawn McCarney  *
1808adc4f0dbSShawn McCarney  * The sensorNames set contains all requested sensors for the current chassis.
1809de629b6eSShawn McCarney  *
1810de629b6eSShawn McCarney  * To minimize the number of DBus calls, the DBus method
1811de629b6eSShawn McCarney  * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1812de629b6eSShawn McCarney  * values of all sensors provided by a connection (service).
1813de629b6eSShawn McCarney  *
1814de629b6eSShawn McCarney  * The connections set contains all the connections that provide sensor values.
1815de629b6eSShawn McCarney  *
1816adc4f0dbSShawn McCarney  * The InventoryItem vector contains D-Bus inventory items associated with the
1817adc4f0dbSShawn McCarney  * sensors.  Inventory item data is needed for some Redfish sensor properties.
1818adc4f0dbSShawn McCarney  *
1819de629b6eSShawn McCarney  * @param SensorsAsyncResp Pointer to object holding response data.
1820adc4f0dbSShawn McCarney  * @param sensorNames All requested sensors within the current chassis.
1821de629b6eSShawn McCarney  * @param connections Connections that provide sensor values.
1822de629b6eSShawn McCarney  * implements ObjectManager.
1823adc4f0dbSShawn McCarney  * @param inventoryItems Inventory items associated with the sensors.
1824de629b6eSShawn McCarney  */
182523a21a1cSEd Tanous inline void getSensorData(
182681ce609eSEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1827fe04d49cSNan Zhou     const std::shared_ptr<std::set<std::string>>& sensorNames,
1828fe04d49cSNan Zhou     const std::set<std::string>& connections,
1829b5a76932SEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems)
1830de629b6eSShawn McCarney {
183162598e31SEd Tanous     BMCWEB_LOG_DEBUG("getSensorData enter");
1832de629b6eSShawn McCarney     // Get managed objects from all services exposing sensors
1833de629b6eSShawn McCarney     for (const std::string& connection : connections)
1834de629b6eSShawn McCarney     {
18355eb468daSGeorge Liu         sdbusplus::message::object_path sensorPath(
18365eb468daSGeorge Liu             "/xyz/openbmc_project/sensors");
18375eb468daSGeorge Liu         dbus::utility::getManagedObjects(
18385eb468daSGeorge Liu             connection, sensorPath,
1839002d39b4SEd Tanous             [sensorsAsyncResp, sensorNames,
18405e7e2dc5SEd Tanous              inventoryItems](const boost::system::error_code& ec,
184102cad96eSEd Tanous                              const dbus::utility::ManagedObjectType& resp) {
184262598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getManagedObjectsCb enter");
1843de629b6eSShawn McCarney                 if (ec)
1844de629b6eSShawn McCarney                 {
184562598e31SEd Tanous                     BMCWEB_LOG_ERROR("getManagedObjectsCb DBUS error: {}", ec);
18468d1b46d7Szhanghch05                     messages::internalError(sensorsAsyncResp->asyncResp->res);
1847de629b6eSShawn McCarney                     return;
1848de629b6eSShawn McCarney                 }
18490c728b42SJanet Adkins                 auto chassisSubNode = sensor_utils::chassisSubNodeFromString(
18500c728b42SJanet Adkins                     sensorsAsyncResp->chassisSubNode);
1851de629b6eSShawn McCarney                 // Go through all objects and update response with sensor data
1852de629b6eSShawn McCarney                 for (const auto& objDictEntry : resp)
1853de629b6eSShawn McCarney                 {
1854de629b6eSShawn McCarney                     const std::string& objPath =
1855de629b6eSShawn McCarney                         static_cast<const std::string&>(objDictEntry.first);
185662598e31SEd Tanous                     BMCWEB_LOG_DEBUG("getManagedObjectsCb parsing object {}",
185762598e31SEd Tanous                                      objPath);
1858de629b6eSShawn McCarney 
1859de629b6eSShawn McCarney                     std::vector<std::string> split;
1860de629b6eSShawn McCarney                     // Reserve space for
1861de629b6eSShawn McCarney                     // /xyz/openbmc_project/sensors/<name>/<subname>
1862de629b6eSShawn McCarney                     split.reserve(6);
186350ebd4afSEd Tanous                     // NOLINTNEXTLINE
186450ebd4afSEd Tanous                     bmcweb::split(split, objPath, '/');
1865de629b6eSShawn McCarney                     if (split.size() < 6)
1866de629b6eSShawn McCarney                     {
186762598e31SEd Tanous                         BMCWEB_LOG_ERROR("Got path that isn't long enough {}",
186862598e31SEd Tanous                                          objPath);
1869de629b6eSShawn McCarney                         continue;
1870de629b6eSShawn McCarney                     }
187150ebd4afSEd Tanous                     // These indexes aren't intuitive, as split puts an empty
1872de629b6eSShawn McCarney                     // string at the beginning
1873de629b6eSShawn McCarney                     const std::string& sensorType = split[4];
1874de629b6eSShawn McCarney                     const std::string& sensorName = split[5];
187562598e31SEd Tanous                     BMCWEB_LOG_DEBUG("sensorName {} sensorType {}", sensorName,
187662598e31SEd Tanous                                      sensorType);
187749c53ac9SJohnathan Mantey                     if (sensorNames->find(objPath) == sensorNames->end())
1878de629b6eSShawn McCarney                     {
187962598e31SEd Tanous                         BMCWEB_LOG_DEBUG("{} not in sensor list ", sensorName);
1880de629b6eSShawn McCarney                         continue;
1881de629b6eSShawn McCarney                     }
1882de629b6eSShawn McCarney 
1883adc4f0dbSShawn McCarney                     // Find inventory item (if any) associated with sensor
1884adc4f0dbSShawn McCarney                     InventoryItem* inventoryItem =
1885adc4f0dbSShawn McCarney                         findInventoryItemForSensor(inventoryItems, objPath);
1886adc4f0dbSShawn McCarney 
188795a3ecadSAnthony Wilson                     const std::string& sensorSchema =
188881ce609eSEd Tanous                         sensorsAsyncResp->chassisSubNode;
188995a3ecadSAnthony Wilson 
189095a3ecadSAnthony Wilson                     nlohmann::json* sensorJson = nullptr;
189195a3ecadSAnthony Wilson 
18920c728b42SJanet Adkins                     if (sensorSchema == sensors::sensorsNodeStr &&
1893928fefb9SNan Zhou                         !sensorsAsyncResp->efficientExpand)
189495a3ecadSAnthony Wilson                     {
18951516c21bSJanet Adkins                         std::string sensorId =
18961516c21bSJanet Adkins                             redfish::sensor_utils::getSensorId(sensorName,
18971516c21bSJanet Adkins                                                                sensorType);
1898c1d019a6SEd Tanous 
1899bd79bce8SPatrick Williams                         sensorsAsyncResp->asyncResp->res
1900bd79bce8SPatrick Williams                             .jsonValue["@odata.id"] = boost::urls::format(
1901bd79bce8SPatrick Williams                             "/redfish/v1/Chassis/{}/{}/{}",
1902c1d019a6SEd Tanous                             sensorsAsyncResp->chassisId,
1903bd79bce8SPatrick Williams                             sensorsAsyncResp->chassisSubNode, sensorId);
1904bd79bce8SPatrick Williams                         sensorJson =
1905bd79bce8SPatrick Williams                             &(sensorsAsyncResp->asyncResp->res.jsonValue);
190695a3ecadSAnthony Wilson                     }
190795a3ecadSAnthony Wilson                     else
190895a3ecadSAnthony Wilson                     {
1909271584abSEd Tanous                         std::string fieldName;
1910928fefb9SNan Zhou                         if (sensorsAsyncResp->efficientExpand)
1911928fefb9SNan Zhou                         {
1912928fefb9SNan Zhou                             fieldName = "Members";
1913928fefb9SNan Zhou                         }
1914928fefb9SNan Zhou                         else if (sensorType == "temperature")
1915de629b6eSShawn McCarney                         {
1916de629b6eSShawn McCarney                             fieldName = "Temperatures";
1917de629b6eSShawn McCarney                         }
1918bd79bce8SPatrick Williams                         else if (sensorType == "fan" ||
1919bd79bce8SPatrick Williams                                  sensorType == "fan_tach" ||
1920de629b6eSShawn McCarney                                  sensorType == "fan_pwm")
1921de629b6eSShawn McCarney                         {
1922de629b6eSShawn McCarney                             fieldName = "Fans";
1923de629b6eSShawn McCarney                         }
1924de629b6eSShawn McCarney                         else if (sensorType == "voltage")
1925de629b6eSShawn McCarney                         {
1926de629b6eSShawn McCarney                             fieldName = "Voltages";
1927de629b6eSShawn McCarney                         }
1928de629b6eSShawn McCarney                         else if (sensorType == "power")
1929de629b6eSShawn McCarney                         {
193055f79e6fSEd Tanous                             if (sensorName == "total_power")
1931028f7ebcSEddie James                             {
1932028f7ebcSEddie James                                 fieldName = "PowerControl";
1933028f7ebcSEddie James                             }
1934adc4f0dbSShawn McCarney                             else if ((inventoryItem != nullptr) &&
1935adc4f0dbSShawn McCarney                                      (inventoryItem->isPowerSupply))
1936028f7ebcSEddie James                             {
1937de629b6eSShawn McCarney                                 fieldName = "PowerSupplies";
1938de629b6eSShawn McCarney                             }
1939adc4f0dbSShawn McCarney                             else
1940adc4f0dbSShawn McCarney                             {
1941adc4f0dbSShawn McCarney                                 // Other power sensors are in SensorCollection
1942adc4f0dbSShawn McCarney                                 continue;
1943adc4f0dbSShawn McCarney                             }
1944028f7ebcSEddie James                         }
1945de629b6eSShawn McCarney                         else
1946de629b6eSShawn McCarney                         {
1947bd79bce8SPatrick Williams                             BMCWEB_LOG_ERROR(
1948bd79bce8SPatrick Williams                                 "Unsure how to handle sensorType {}",
194962598e31SEd Tanous                                 sensorType);
1950de629b6eSShawn McCarney                             continue;
1951de629b6eSShawn McCarney                         }
1952de629b6eSShawn McCarney 
1953de629b6eSShawn McCarney                         nlohmann::json& tempArray =
1954bd79bce8SPatrick Williams                             sensorsAsyncResp->asyncResp->res
1955bd79bce8SPatrick Williams                                 .jsonValue[fieldName];
1956adc4f0dbSShawn McCarney                         if (fieldName == "PowerControl")
195749c53ac9SJohnathan Mantey                         {
1958adc4f0dbSShawn McCarney                             if (tempArray.empty())
19597ab06f49SGunnar Mills                             {
196095a3ecadSAnthony Wilson                                 // Put multiple "sensors" into a single
196195a3ecadSAnthony Wilson                                 // PowerControl. Follows MemberId naming and
196295a3ecadSAnthony Wilson                                 // naming in power.hpp.
19631476687dSEd Tanous                                 nlohmann::json::object_t power;
1964ef4c65b7SEd Tanous                                 boost::urls::url url = boost::urls::format(
1965ef4c65b7SEd Tanous                                     "/redfish/v1/Chassis/{}/{}",
1966eddfc437SWilly Tu                                     sensorsAsyncResp->chassisId,
1967eddfc437SWilly Tu                                     sensorsAsyncResp->chassisSubNode);
1968bd79bce8SPatrick Williams                                 url.set_fragment(
1969bd79bce8SPatrick Williams                                     (""_json_pointer / fieldName / "0")
1970eddfc437SWilly Tu                                         .to_string());
1971eddfc437SWilly Tu                                 power["@odata.id"] = std::move(url);
1972b2ba3072SPatrick Williams                                 tempArray.emplace_back(std::move(power));
1973adc4f0dbSShawn McCarney                             }
1974adc4f0dbSShawn McCarney                             sensorJson = &(tempArray.back());
1975adc4f0dbSShawn McCarney                         }
1976adc4f0dbSShawn McCarney                         else if (fieldName == "PowerSupplies")
1977adc4f0dbSShawn McCarney                         {
1978adc4f0dbSShawn McCarney                             if (inventoryItem != nullptr)
1979adc4f0dbSShawn McCarney                             {
1980bd79bce8SPatrick Williams                                 sensorJson = &(getPowerSupply(
1981bd79bce8SPatrick Williams                                     tempArray, *inventoryItem,
198281ce609eSEd Tanous                                     sensorsAsyncResp->chassisId));
1983adc4f0dbSShawn McCarney                             }
198449c53ac9SJohnathan Mantey                         }
1985928fefb9SNan Zhou                         else if (fieldName == "Members")
1986928fefb9SNan Zhou                         {
19871516c21bSJanet Adkins                             std::string sensorId =
19881516c21bSJanet Adkins                                 redfish::sensor_utils::getSensorId(sensorName,
19891516c21bSJanet Adkins                                                                    sensorType);
1990677bb756SEd Tanous 
19911476687dSEd Tanous                             nlohmann::json::object_t member;
1992ef4c65b7SEd Tanous                             member["@odata.id"] = boost::urls::format(
1993ef4c65b7SEd Tanous                                 "/redfish/v1/Chassis/{}/{}/{}",
1994677bb756SEd Tanous                                 sensorsAsyncResp->chassisId,
1995677bb756SEd Tanous                                 sensorsAsyncResp->chassisSubNode, sensorId);
1996b2ba3072SPatrick Williams                             tempArray.emplace_back(std::move(member));
1997928fefb9SNan Zhou                             sensorJson = &(tempArray.back());
1998928fefb9SNan Zhou                         }
199949c53ac9SJohnathan Mantey                         else
200049c53ac9SJohnathan Mantey                         {
20011476687dSEd Tanous                             nlohmann::json::object_t member;
2002ef4c65b7SEd Tanous                             boost::urls::url url = boost::urls::format(
2003ef4c65b7SEd Tanous                                 "/redfish/v1/Chassis/{}/{}",
2004eddfc437SWilly Tu                                 sensorsAsyncResp->chassisId,
2005eddfc437SWilly Tu                                 sensorsAsyncResp->chassisSubNode);
2006eddfc437SWilly Tu                             url.set_fragment(
2007eddfc437SWilly Tu                                 (""_json_pointer / fieldName).to_string());
2008eddfc437SWilly Tu                             member["@odata.id"] = std::move(url);
2009b2ba3072SPatrick Williams                             tempArray.emplace_back(std::move(member));
2010adc4f0dbSShawn McCarney                             sensorJson = &(tempArray.back());
201149c53ac9SJohnathan Mantey                         }
201295a3ecadSAnthony Wilson                     }
2013de629b6eSShawn McCarney 
2014adc4f0dbSShawn McCarney                     if (sensorJson != nullptr)
2015adc4f0dbSShawn McCarney                     {
20160c728b42SJanet Adkins                         objectInterfacesToJson(
20170c728b42SJanet Adkins                             sensorName, sensorType, chassisSubNode,
20180c728b42SJanet Adkins                             objDictEntry.second, *sensorJson, inventoryItem);
20191d7c0054SEd Tanous 
20201d7c0054SEd Tanous                         std::string path = "/xyz/openbmc_project/sensors/";
20211d7c0054SEd Tanous                         path += sensorType;
20221d7c0054SEd Tanous                         path += "/";
20231d7c0054SEd Tanous                         path += sensorName;
2024c1d019a6SEd Tanous                         sensorsAsyncResp->addMetadata(*sensorJson, path);
2025adc4f0dbSShawn McCarney                     }
2026de629b6eSShawn McCarney                 }
202781ce609eSEd Tanous                 if (sensorsAsyncResp.use_count() == 1)
202849c53ac9SJohnathan Mantey                 {
202981ce609eSEd Tanous                     sortJSONResponse(sensorsAsyncResp);
20300c728b42SJanet Adkins                     if (chassisSubNode ==
20310c728b42SJanet Adkins                             sensor_utils::ChassisSubNode::sensorsNode &&
2032928fefb9SNan Zhou                         sensorsAsyncResp->efficientExpand)
2033928fefb9SNan Zhou                     {
2034928fefb9SNan Zhou                         sensorsAsyncResp->asyncResp->res
2035928fefb9SNan Zhou                             .jsonValue["Members@odata.count"] =
2036bd79bce8SPatrick Williams                             sensorsAsyncResp->asyncResp->res
2037bd79bce8SPatrick Williams                                 .jsonValue["Members"]
2038928fefb9SNan Zhou                                 .size();
2039928fefb9SNan Zhou                     }
20400c728b42SJanet Adkins                     else if (chassisSubNode ==
20410c728b42SJanet Adkins                              sensor_utils::ChassisSubNode::thermalNode)
20428bd25ccdSJames Feist                     {
204381ce609eSEd Tanous                         populateFanRedundancy(sensorsAsyncResp);
20448bd25ccdSJames Feist                     }
204549c53ac9SJohnathan Mantey                 }
204662598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getManagedObjectsCb exit");
20475eb468daSGeorge Liu             });
204823a21a1cSEd Tanous     }
204962598e31SEd Tanous     BMCWEB_LOG_DEBUG("getSensorData exit");
2050de629b6eSShawn McCarney }
2051de629b6eSShawn McCarney 
2052fe04d49cSNan Zhou inline void
2053fe04d49cSNan Zhou     processSensorList(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
2054fe04d49cSNan Zhou                       const std::shared_ptr<std::set<std::string>>& sensorNames)
20551abe55efSEd Tanous {
2056fe04d49cSNan Zhou     auto getConnectionCb = [sensorsAsyncResp, sensorNames](
2057fe04d49cSNan Zhou                                const std::set<std::string>& connections) {
205862598e31SEd Tanous         BMCWEB_LOG_DEBUG("getConnectionCb enter");
2059adc4f0dbSShawn McCarney         auto getInventoryItemsCb =
2060bd79bce8SPatrick Williams             [sensorsAsyncResp, sensorNames, connections](
2061bd79bce8SPatrick Williams                 const std::shared_ptr<std::vector<InventoryItem>>&
20624e0d8789SEd Tanous                     inventoryItems) mutable {
206362598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryItemsCb enter");
206449c53ac9SJohnathan Mantey                 // Get sensor data and store results in JSON
2065002d39b4SEd Tanous                 getSensorData(sensorsAsyncResp, sensorNames, connections,
2066d0090733SEd Tanous                               inventoryItems);
206762598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryItemsCb exit");
2068adc4f0dbSShawn McCarney             };
2069adc4f0dbSShawn McCarney 
2070adc4f0dbSShawn McCarney         // Get inventory items associated with sensors
2071d0090733SEd Tanous         getInventoryItems(sensorsAsyncResp, sensorNames,
2072adc4f0dbSShawn McCarney                           std::move(getInventoryItemsCb));
2073adc4f0dbSShawn McCarney 
207462598e31SEd Tanous         BMCWEB_LOG_DEBUG("getConnectionCb exit");
207508777fb0SLewanczyk, Dawid     };
2076de629b6eSShawn McCarney 
2077de629b6eSShawn McCarney     // Get set of connections that provide sensor values
207881ce609eSEd Tanous     getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb));
207995a3ecadSAnthony Wilson }
208095a3ecadSAnthony Wilson 
208195a3ecadSAnthony Wilson /**
208295a3ecadSAnthony Wilson  * @brief Entry point for retrieving sensors data related to requested
208395a3ecadSAnthony Wilson  *        chassis.
208495a3ecadSAnthony Wilson  * @param SensorsAsyncResp   Pointer to object holding response data
208595a3ecadSAnthony Wilson  */
2086b5a76932SEd Tanous inline void
208781ce609eSEd Tanous     getChassisData(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
208895a3ecadSAnthony Wilson {
208962598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassisData enter");
209095a3ecadSAnthony Wilson     auto getChassisCb =
209181ce609eSEd Tanous         [sensorsAsyncResp](
2092fe04d49cSNan Zhou             const std::shared_ptr<std::set<std::string>>& sensorNames) {
209362598e31SEd Tanous             BMCWEB_LOG_DEBUG("getChassisCb enter");
209481ce609eSEd Tanous             processSensorList(sensorsAsyncResp, sensorNames);
209562598e31SEd Tanous             BMCWEB_LOG_DEBUG("getChassisCb exit");
209608777fb0SLewanczyk, Dawid         };
2097928fefb9SNan Zhou     // SensorCollection doesn't contain the Redundancy property
20980c728b42SJanet Adkins     if (sensorsAsyncResp->chassisSubNode != sensors::sensorsNodeStr)
2099928fefb9SNan Zhou     {
21008d1b46d7Szhanghch05         sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
21018d1b46d7Szhanghch05             nlohmann::json::array();
2102928fefb9SNan Zhou     }
210326f03899SShawn McCarney     // Get set of sensors in chassis
21047f1cc26dSEd Tanous     getChassis(sensorsAsyncResp->asyncResp, sensorsAsyncResp->chassisId,
21057f1cc26dSEd Tanous                sensorsAsyncResp->chassisSubNode, sensorsAsyncResp->types,
21067f1cc26dSEd Tanous                std::move(getChassisCb));
210762598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassisData exit");
2108271584abSEd Tanous }
210908777fb0SLewanczyk, Dawid 
2110413961deSRichard Marian Thomaiyar /**
211149c53ac9SJohnathan Mantey  * @brief Find the requested sensorName in the list of all sensors supplied by
211249c53ac9SJohnathan Mantey  * the chassis node
211349c53ac9SJohnathan Mantey  *
211449c53ac9SJohnathan Mantey  * @param sensorName   The sensor name supplied in the PATCH request
211549c53ac9SJohnathan Mantey  * @param sensorsList  The list of sensors managed by the chassis node
211649c53ac9SJohnathan Mantey  * @param sensorsModified  The list of sensors that were found as a result of
211749c53ac9SJohnathan Mantey  *                         repeated calls to this function
211849c53ac9SJohnathan Mantey  */
2119bd79bce8SPatrick Williams inline bool findSensorNameUsingSensorPath(
2120bd79bce8SPatrick Williams     std::string_view sensorName, const std::set<std::string>& sensorsList,
2121fe04d49cSNan Zhou     std::set<std::string>& sensorsModified)
212249c53ac9SJohnathan Mantey {
2123fe04d49cSNan Zhou     for (const auto& chassisSensor : sensorsList)
212449c53ac9SJohnathan Mantey     {
212528aa8de5SGeorge Liu         sdbusplus::message::object_path path(chassisSensor);
2126b00dcc27SEd Tanous         std::string thisSensorName = path.filename();
212728aa8de5SGeorge Liu         if (thisSensorName.empty())
212849c53ac9SJohnathan Mantey         {
212949c53ac9SJohnathan Mantey             continue;
213049c53ac9SJohnathan Mantey         }
213149c53ac9SJohnathan Mantey         if (thisSensorName == sensorName)
213249c53ac9SJohnathan Mantey         {
213349c53ac9SJohnathan Mantey             sensorsModified.emplace(chassisSensor);
213449c53ac9SJohnathan Mantey             return true;
213549c53ac9SJohnathan Mantey         }
213649c53ac9SJohnathan Mantey     }
213749c53ac9SJohnathan Mantey     return false;
213849c53ac9SJohnathan Mantey }
213949c53ac9SJohnathan Mantey 
214049c53ac9SJohnathan Mantey /**
2141413961deSRichard Marian Thomaiyar  * @brief Entry point for overriding sensor values of given sensor
2142413961deSRichard Marian Thomaiyar  *
21438d1b46d7Szhanghch05  * @param sensorAsyncResp   response object
21444bb3dc34SCarol Wang  * @param allCollections   Collections extract from sensors' request patch info
2145413961deSRichard Marian Thomaiyar  * @param chassisSubNode   Chassis Node for which the query has to happen
2146413961deSRichard Marian Thomaiyar  */
214723a21a1cSEd Tanous inline void setSensorsOverride(
2148b5a76932SEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
21490885057cSEd Tanous     std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>&
2150397fd61fSjayaprakash Mutyala         allCollections)
2151413961deSRichard Marian Thomaiyar {
215262598e31SEd Tanous     BMCWEB_LOG_INFO("setSensorsOverride for subNode{}",
215362598e31SEd Tanous                     sensorAsyncResp->chassisSubNode);
2154413961deSRichard Marian Thomaiyar 
2155d02aad39SEd Tanous     std::string_view propertyValueName;
2156f65af9e8SRichard Marian Thomaiyar     std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
2157413961deSRichard Marian Thomaiyar     std::string memberId;
2158543f4400SEd Tanous     double value = 0.0;
2159f65af9e8SRichard Marian Thomaiyar     for (auto& collectionItems : allCollections)
2160f65af9e8SRichard Marian Thomaiyar     {
2161f65af9e8SRichard Marian Thomaiyar         if (collectionItems.first == "Temperatures")
2162f65af9e8SRichard Marian Thomaiyar         {
2163f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingCelsius";
2164f65af9e8SRichard Marian Thomaiyar         }
2165f65af9e8SRichard Marian Thomaiyar         else if (collectionItems.first == "Fans")
2166f65af9e8SRichard Marian Thomaiyar         {
2167f65af9e8SRichard Marian Thomaiyar             propertyValueName = "Reading";
2168f65af9e8SRichard Marian Thomaiyar         }
2169f65af9e8SRichard Marian Thomaiyar         else
2170f65af9e8SRichard Marian Thomaiyar         {
2171f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingVolts";
2172f65af9e8SRichard Marian Thomaiyar         }
2173f65af9e8SRichard Marian Thomaiyar         for (auto& item : collectionItems.second)
2174f65af9e8SRichard Marian Thomaiyar         {
2175afc474aeSMyung Bae             if (!json_util::readJsonObject( //
2176afc474aeSMyung Bae                     item, sensorAsyncResp->asyncResp->res, //
2177afc474aeSMyung Bae                     "MemberId", memberId, //
2178afc474aeSMyung Bae                     propertyValueName, value //
2179afc474aeSMyung Bae                     ))
2180413961deSRichard Marian Thomaiyar             {
2181413961deSRichard Marian Thomaiyar                 return;
2182413961deSRichard Marian Thomaiyar             }
2183f65af9e8SRichard Marian Thomaiyar             overrideMap.emplace(memberId,
2184f65af9e8SRichard Marian Thomaiyar                                 std::make_pair(value, collectionItems.first));
2185f65af9e8SRichard Marian Thomaiyar         }
2186f65af9e8SRichard Marian Thomaiyar     }
21874bb3dc34SCarol Wang 
2188bd79bce8SPatrick Williams     auto getChassisSensorListCb = [sensorAsyncResp, overrideMap,
2189bd79bce8SPatrick Williams                                    propertyValueNameStr =
2190bd79bce8SPatrick Williams                                        std::string(propertyValueName)](
2191bd79bce8SPatrick Williams                                       const std::shared_ptr<
2192bd79bce8SPatrick Williams                                           std::set<std::string>>& sensorsList) {
219349c53ac9SJohnathan Mantey         // Match sensor names in the PATCH request to those managed by the
219449c53ac9SJohnathan Mantey         // chassis node
2195fe04d49cSNan Zhou         const std::shared_ptr<std::set<std::string>> sensorNames =
2196fe04d49cSNan Zhou             std::make_shared<std::set<std::string>>();
2197f65af9e8SRichard Marian Thomaiyar         for (const auto& item : overrideMap)
2198413961deSRichard Marian Thomaiyar         {
2199f65af9e8SRichard Marian Thomaiyar             const auto& sensor = item.first;
2200c71d6125SEd Tanous             std::pair<std::string, std::string> sensorNameType =
22011516c21bSJanet Adkins                 redfish::sensor_utils::splitSensorNameAndType(sensor);
2202c71d6125SEd Tanous             if (!findSensorNameUsingSensorPath(sensorNameType.second,
2203c71d6125SEd Tanous                                                *sensorsList, *sensorNames))
2204f65af9e8SRichard Marian Thomaiyar             {
220562598e31SEd Tanous                 BMCWEB_LOG_INFO("Unable to find memberId {}", item.first);
22068d1b46d7Szhanghch05                 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
2207f65af9e8SRichard Marian Thomaiyar                                            item.second.second, item.first);
2208413961deSRichard Marian Thomaiyar                 return;
2209413961deSRichard Marian Thomaiyar             }
2210f65af9e8SRichard Marian Thomaiyar         }
2211413961deSRichard Marian Thomaiyar         // Get the connection to which the memberId belongs
2212bd79bce8SPatrick Williams         auto getObjectsWithConnectionCb = [sensorAsyncResp, overrideMap,
2213bd79bce8SPatrick Williams                                            propertyValueNameStr](
2214bd79bce8SPatrick Williams                                               const std::set<
2215bd79bce8SPatrick Williams                                                   std::string>& /*connections*/,
2216bd79bce8SPatrick Williams                                               const std::set<std::pair<
2217bd79bce8SPatrick Williams                                                   std::string, std::string>>&
2218413961deSRichard Marian Thomaiyar                                                   objectsWithConnection) {
2219f65af9e8SRichard Marian Thomaiyar             if (objectsWithConnection.size() != overrideMap.size())
2220413961deSRichard Marian Thomaiyar             {
222162598e31SEd Tanous                 BMCWEB_LOG_INFO(
222262598e31SEd Tanous                     "Unable to find all objects with proper connection {} requested {}",
222362598e31SEd Tanous                     objectsWithConnection.size(), overrideMap.size());
2224bd79bce8SPatrick Williams                 messages::resourceNotFound(
2225bd79bce8SPatrick Williams                     sensorAsyncResp->asyncResp->res,
22260c728b42SJanet Adkins                     sensorAsyncResp->chassisSubNode == sensors::thermalNodeStr
2227413961deSRichard Marian Thomaiyar                         ? "Temperatures"
2228413961deSRichard Marian Thomaiyar                         : "Voltages",
2229f65af9e8SRichard Marian Thomaiyar                     "Count");
2230f65af9e8SRichard Marian Thomaiyar                 return;
2231f65af9e8SRichard Marian Thomaiyar             }
2232f65af9e8SRichard Marian Thomaiyar             for (const auto& item : objectsWithConnection)
2233f65af9e8SRichard Marian Thomaiyar             {
223428aa8de5SGeorge Liu                 sdbusplus::message::object_path path(item.first);
223528aa8de5SGeorge Liu                 std::string sensorName = path.filename();
223628aa8de5SGeorge Liu                 if (sensorName.empty())
2237f65af9e8SRichard Marian Thomaiyar                 {
22384f277b54SJayaprakash Mutyala                     messages::internalError(sensorAsyncResp->asyncResp->res);
2239f65af9e8SRichard Marian Thomaiyar                     return;
2240f65af9e8SRichard Marian Thomaiyar                 }
22411516c21bSJanet Adkins                 std::string id = redfish::sensor_utils::getSensorId(
22421516c21bSJanet Adkins                     sensorName, path.parent_path().filename());
2243f65af9e8SRichard Marian Thomaiyar 
22443f5eb755SBan Feng                 const auto& iterator = overrideMap.find(id);
2245f65af9e8SRichard Marian Thomaiyar                 if (iterator == overrideMap.end())
2246f65af9e8SRichard Marian Thomaiyar                 {
224762598e31SEd Tanous                     BMCWEB_LOG_INFO("Unable to find sensor object{}",
224862598e31SEd Tanous                                     item.first);
22494f277b54SJayaprakash Mutyala                     messages::internalError(sensorAsyncResp->asyncResp->res);
2250413961deSRichard Marian Thomaiyar                     return;
2251413961deSRichard Marian Thomaiyar                 }
2252e93abac6SGinu George                 setDbusProperty(sensorAsyncResp->asyncResp,
2253e93abac6SGinu George                                 propertyValueNameStr, item.second, item.first,
2254e93abac6SGinu George                                 "xyz.openbmc_project.Sensor.Value", "Value",
2255d02aad39SEd Tanous                                 iterator->second.first);
2256f65af9e8SRichard Marian Thomaiyar             }
2257413961deSRichard Marian Thomaiyar         };
2258413961deSRichard Marian Thomaiyar         // Get object with connection for the given sensor name
2259413961deSRichard Marian Thomaiyar         getObjectsWithConnection(sensorAsyncResp, sensorNames,
2260413961deSRichard Marian Thomaiyar                                  std::move(getObjectsWithConnectionCb));
2261413961deSRichard Marian Thomaiyar     };
2262413961deSRichard Marian Thomaiyar     // get full sensor list for the given chassisId and cross verify the sensor.
22637f1cc26dSEd Tanous     getChassis(sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId,
22647f1cc26dSEd Tanous                sensorAsyncResp->chassisSubNode, sensorAsyncResp->types,
22657f1cc26dSEd Tanous                std::move(getChassisSensorListCb));
2266413961deSRichard Marian Thomaiyar }
2267413961deSRichard Marian Thomaiyar 
2268a0ec28b6SAdrian Ambrożewicz /**
2269a0ec28b6SAdrian Ambrożewicz  * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus
2270a0ec28b6SAdrian Ambrożewicz  * path of the sensor.
2271a0ec28b6SAdrian Ambrożewicz  *
2272a0ec28b6SAdrian Ambrożewicz  * Function builds valid Redfish response for sensor query of given chassis and
2273a0ec28b6SAdrian Ambrożewicz  * node. It then builds metadata about Redfish<->D-Bus correlations and provides
2274a0ec28b6SAdrian Ambrożewicz  * it to caller in a callback.
2275a0ec28b6SAdrian Ambrożewicz  *
2276a0ec28b6SAdrian Ambrożewicz  * @param chassis   Chassis for which retrieval should be performed
2277c9563608SJanet Adkins  * @param node  Node (group) of sensors. See sensor_utils::node for supported
2278c9563608SJanet Adkins  * values
2279a0ec28b6SAdrian Ambrożewicz  * @param mapComplete   Callback to be called with retrieval result
2280a0ec28b6SAdrian Ambrożewicz  */
2281931edc79SEd Tanous template <typename Callback>
2282bd79bce8SPatrick Williams inline void retrieveUriToDbusMap(
2283bd79bce8SPatrick Williams     const std::string& chassis, const std::string& node, Callback&& mapComplete)
2284a0ec28b6SAdrian Ambrożewicz {
228502da7c5aSEd Tanous     decltype(sensors::paths)::const_iterator pathIt =
228602da7c5aSEd Tanous         std::find_if(sensors::paths.cbegin(), sensors::paths.cend(),
228702da7c5aSEd Tanous                      [&node](auto&& val) { return val.first == node; });
228802da7c5aSEd Tanous     if (pathIt == sensors::paths.cend())
2289a0ec28b6SAdrian Ambrożewicz     {
229062598e31SEd Tanous         BMCWEB_LOG_ERROR("Wrong node provided : {}", node);
22916804b5c8SEd Tanous         std::map<std::string, std::string> noop;
22926804b5c8SEd Tanous         mapComplete(boost::beast::http::status::bad_request, noop);
2293a0ec28b6SAdrian Ambrożewicz         return;
2294a0ec28b6SAdrian Ambrożewicz     }
2295d51e072fSKrzysztof Grobelny 
229672374eb7SNan Zhou     auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
2297bd79bce8SPatrick Williams     auto callback =
2298bd79bce8SPatrick Williams         [asyncResp, mapCompleteCb = std::forward<Callback>(mapComplete)](
2299a0ec28b6SAdrian Ambrożewicz             const boost::beast::http::status status,
2300fe04d49cSNan Zhou             const std::map<std::string, std::string>& uriToDbus) {
2301fe04d49cSNan Zhou             mapCompleteCb(status, uriToDbus);
2302fe04d49cSNan Zhou         };
2303a0ec28b6SAdrian Ambrożewicz 
2304a0ec28b6SAdrian Ambrożewicz     auto resp = std::make_shared<SensorsAsyncResp>(
2305d51e072fSKrzysztof Grobelny         asyncResp, chassis, pathIt->second, node, std::move(callback));
2306a0ec28b6SAdrian Ambrożewicz     getChassisData(resp);
2307a0ec28b6SAdrian Ambrożewicz }
2308a0ec28b6SAdrian Ambrożewicz 
2309bacb2162SNan Zhou namespace sensors
2310bacb2162SNan Zhou {
2311928fefb9SNan Zhou 
2312bacb2162SNan Zhou inline void getChassisCallback(
2313c1d019a6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2314c1d019a6SEd Tanous     std::string_view chassisId, std::string_view chassisSubNode,
2315fe04d49cSNan Zhou     const std::shared_ptr<std::set<std::string>>& sensorNames)
2316bacb2162SNan Zhou {
231762598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassisCallback enter ");
2318bacb2162SNan Zhou 
2319c1d019a6SEd Tanous     nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
2320c1d019a6SEd Tanous     for (const std::string& sensor : *sensorNames)
2321bacb2162SNan Zhou     {
232262598e31SEd Tanous         BMCWEB_LOG_DEBUG("Adding sensor: {}", sensor);
2323bacb2162SNan Zhou 
2324bacb2162SNan Zhou         sdbusplus::message::object_path path(sensor);
2325bacb2162SNan Zhou         std::string sensorName = path.filename();
2326bacb2162SNan Zhou         if (sensorName.empty())
2327bacb2162SNan Zhou         {
232862598e31SEd Tanous             BMCWEB_LOG_ERROR("Invalid sensor path: {}", sensor);
2329c1d019a6SEd Tanous             messages::internalError(asyncResp->res);
2330bacb2162SNan Zhou             return;
2331bacb2162SNan Zhou         }
2332c1d019a6SEd Tanous         std::string type = path.parent_path().filename();
23331516c21bSJanet Adkins         std::string id = redfish::sensor_utils::getSensorId(sensorName, type);
2334c1d019a6SEd Tanous 
23351476687dSEd Tanous         nlohmann::json::object_t member;
2336ef4c65b7SEd Tanous         member["@odata.id"] = boost::urls::format(
2337ef4c65b7SEd Tanous             "/redfish/v1/Chassis/{}/{}/{}", chassisId, chassisSubNode, id);
2338c1d019a6SEd Tanous 
2339b2ba3072SPatrick Williams         entriesArray.emplace_back(std::move(member));
2340bacb2162SNan Zhou     }
2341bacb2162SNan Zhou 
2342c1d019a6SEd Tanous     asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
234362598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassisCallback exit");
2344bacb2162SNan Zhou }
2345e6bd846dSNan Zhou 
2346ac106bf6SEd Tanous inline void handleSensorCollectionGet(
2347ac106bf6SEd Tanous     App& app, const crow::Request& req,
2348ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2349de167a6fSNan Zhou     const std::string& chassisId)
2350de167a6fSNan Zhou {
2351de167a6fSNan Zhou     query_param::QueryCapabilities capabilities = {
2352de167a6fSNan Zhou         .canDelegateExpandLevel = 1,
2353de167a6fSNan Zhou     };
2354de167a6fSNan Zhou     query_param::Query delegatedQuery;
2355ac106bf6SEd Tanous     if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
2356de167a6fSNan Zhou                                                   delegatedQuery, capabilities))
2357de167a6fSNan Zhou     {
2358de167a6fSNan Zhou         return;
2359de167a6fSNan Zhou     }
2360de167a6fSNan Zhou 
2361de167a6fSNan Zhou     if (delegatedQuery.expandType != query_param::ExpandType::None)
2362de167a6fSNan Zhou     {
2363de167a6fSNan Zhou         // we perform efficient expand.
2364ac106bf6SEd Tanous         auto sensorsAsyncResp = std::make_shared<SensorsAsyncResp>(
2365ac106bf6SEd Tanous             asyncResp, chassisId, sensors::dbus::sensorPaths,
23660c728b42SJanet Adkins             sensors::sensorsNodeStr,
2367de167a6fSNan Zhou             /*efficientExpand=*/true);
2368ac106bf6SEd Tanous         getChassisData(sensorsAsyncResp);
2369de167a6fSNan Zhou 
237062598e31SEd Tanous         BMCWEB_LOG_DEBUG(
237162598e31SEd Tanous             "SensorCollection doGet exit via efficient expand handler");
2372de167a6fSNan Zhou         return;
23730bad320cSEd Tanous     }
2374de167a6fSNan Zhou 
2375de167a6fSNan Zhou     // We get all sensors as hyperlinkes in the chassis (this
2376de167a6fSNan Zhou     // implies we reply on the default query parameters handler)
23770c728b42SJanet Adkins     getChassis(asyncResp, chassisId, sensors::sensorsNodeStr, dbus::sensorPaths,
2378ac106bf6SEd Tanous                std::bind_front(sensors::getChassisCallback, asyncResp,
23790c728b42SJanet Adkins                                chassisId, sensors::sensorsNodeStr));
2380c1d019a6SEd Tanous }
23817f1cc26dSEd Tanous 
2382c1d019a6SEd Tanous inline void
2383c1d019a6SEd Tanous     getSensorFromDbus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2384c1d019a6SEd Tanous                       const std::string& sensorPath,
2385c1d019a6SEd Tanous                       const ::dbus::utility::MapperGetObject& mapperResponse)
2386c1d019a6SEd Tanous {
2387c1d019a6SEd Tanous     if (mapperResponse.size() != 1)
2388c1d019a6SEd Tanous     {
2389c1d019a6SEd Tanous         messages::internalError(asyncResp->res);
2390c1d019a6SEd Tanous         return;
2391c1d019a6SEd Tanous     }
2392c1d019a6SEd Tanous     const auto& valueIface = *mapperResponse.begin();
2393c1d019a6SEd Tanous     const std::string& connectionName = valueIface.first;
239462598e31SEd Tanous     BMCWEB_LOG_DEBUG("Looking up {}", connectionName);
239562598e31SEd Tanous     BMCWEB_LOG_DEBUG("Path {}", sensorPath);
2396c1343bf6SKrzysztof Grobelny 
2397deae6a78SEd Tanous     ::dbus::utility::getAllProperties(
2398c1343bf6SKrzysztof Grobelny         *crow::connections::systemBus, connectionName, sensorPath, "",
2399c1d019a6SEd Tanous         [asyncResp,
24005e7e2dc5SEd Tanous          sensorPath](const boost::system::error_code& ec,
2401c1d019a6SEd Tanous                      const ::dbus::utility::DBusPropertiesMap& valuesDict) {
2402c1d019a6SEd Tanous             if (ec)
2403c1d019a6SEd Tanous             {
2404c1d019a6SEd Tanous                 messages::internalError(asyncResp->res);
2405c1d019a6SEd Tanous                 return;
2406c1d019a6SEd Tanous             }
2407c1d019a6SEd Tanous             sdbusplus::message::object_path path(sensorPath);
2408c1d019a6SEd Tanous             std::string name = path.filename();
2409c1d019a6SEd Tanous             path = path.parent_path();
2410c1d019a6SEd Tanous             std::string type = path.filename();
2411c9563608SJanet Adkins             sensor_utils::objectPropertiesToJson(
24120c728b42SJanet Adkins                 name, type, sensor_utils::ChassisSubNode::sensorsNode,
24130c728b42SJanet Adkins                 valuesDict, asyncResp->res.jsonValue, nullptr);
2414c1343bf6SKrzysztof Grobelny         });
2415de167a6fSNan Zhou }
2416de167a6fSNan Zhou 
2417e6bd846dSNan Zhou inline void handleSensorGet(App& app, const crow::Request& req,
2418c1d019a6SEd Tanous                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2419677bb756SEd Tanous                             const std::string& chassisId,
2420c1d019a6SEd Tanous                             const std::string& sensorId)
2421e6bd846dSNan Zhou {
2422c1d019a6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2423e6bd846dSNan Zhou     {
2424e6bd846dSNan Zhou         return;
2425e6bd846dSNan Zhou     }
2426c71d6125SEd Tanous     std::pair<std::string, std::string> nameType =
24271516c21bSJanet Adkins         redfish::sensor_utils::splitSensorNameAndType(sensorId);
2428c71d6125SEd Tanous     if (nameType.first.empty() || nameType.second.empty())
2429c1d019a6SEd Tanous     {
2430c1d019a6SEd Tanous         messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2431c1d019a6SEd Tanous         return;
2432c1d019a6SEd Tanous     }
2433c71d6125SEd Tanous 
2434ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2435ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/Sensors/{}", chassisId, sensorId);
2436c1d019a6SEd Tanous 
243762598e31SEd Tanous     BMCWEB_LOG_DEBUG("Sensor doGet enter");
2438e6bd846dSNan Zhou 
24392b73119cSGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
2440e6bd846dSNan Zhou         "xyz.openbmc_project.Sensor.Value"};
2441c71d6125SEd Tanous     std::string sensorPath = "/xyz/openbmc_project/sensors/" + nameType.first +
2442c71d6125SEd Tanous                              '/' + nameType.second;
2443e6bd846dSNan Zhou     // Get a list of all of the sensors that implement Sensor.Value
2444e6bd846dSNan Zhou     // and get the path and service name associated with the sensor
24452b73119cSGeorge Liu     ::dbus::utility::getDbusObject(
24462b73119cSGeorge Liu         sensorPath, interfaces,
2447aec0ec30SMyung Bae         [asyncResp, sensorId,
24482b73119cSGeorge Liu          sensorPath](const boost::system::error_code& ec,
2449c1d019a6SEd Tanous                      const ::dbus::utility::MapperGetObject& subtree) {
245062598e31SEd Tanous             BMCWEB_LOG_DEBUG("respHandler1 enter");
2451aec0ec30SMyung Bae             if (ec == boost::system::errc::io_error)
2452aec0ec30SMyung Bae             {
245362598e31SEd Tanous                 BMCWEB_LOG_WARNING("Sensor not found from getSensorPaths");
2454aec0ec30SMyung Bae                 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2455aec0ec30SMyung Bae                 return;
2456aec0ec30SMyung Bae             }
2457e6bd846dSNan Zhou             if (ec)
2458e6bd846dSNan Zhou             {
2459c1d019a6SEd Tanous                 messages::internalError(asyncResp->res);
246062598e31SEd Tanous                 BMCWEB_LOG_ERROR(
246162598e31SEd Tanous                     "Sensor getSensorPaths resp_handler: Dbus error {}", ec);
2462e6bd846dSNan Zhou                 return;
2463e6bd846dSNan Zhou             }
2464c1d019a6SEd Tanous             getSensorFromDbus(asyncResp, sensorPath, subtree);
246562598e31SEd Tanous             BMCWEB_LOG_DEBUG("respHandler1 exit");
24662b73119cSGeorge Liu         });
2467e6bd846dSNan Zhou }
2468e6bd846dSNan Zhou 
2469bacb2162SNan Zhou } // namespace sensors
2470bacb2162SNan Zhou 
24717e860f15SJohn Edward Broadbent inline void requestRoutesSensorCollection(App& app)
247295a3ecadSAnthony Wilson {
24737e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
2474ed398213SEd Tanous         .privileges(redfish::privileges::getSensorCollection)
2475002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
2476de167a6fSNan Zhou             std::bind_front(sensors::handleSensorCollectionGet, std::ref(app)));
247795a3ecadSAnthony Wilson }
247895a3ecadSAnthony Wilson 
24797e860f15SJohn Edward Broadbent inline void requestRoutesSensor(App& app)
248095a3ecadSAnthony Wilson {
24817e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/")
2482ed398213SEd Tanous         .privileges(redfish::privileges::getSensor)
2483002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
2484e6bd846dSNan Zhou             std::bind_front(sensors::handleSensorGet, std::ref(app)));
248595a3ecadSAnthony Wilson }
248695a3ecadSAnthony Wilson 
248708777fb0SLewanczyk, Dawid } // namespace redfish
2488