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