xref: /openbmc/bmcweb/features/redfish/lib/sensors.hpp (revision deae6a789444debc4724fb6902fc5def299afbee)
108777fb0SLewanczyk, Dawid /*
26be832e2SEd Tanous Copyright (c) 2018 Intel Corporation
36be832e2SEd Tanous 
46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License");
56be832e2SEd Tanous you may not use this file except in compliance with the License.
66be832e2SEd Tanous You may obtain a copy of the License at
76be832e2SEd Tanous 
86be832e2SEd Tanous       http://www.apache.org/licenses/LICENSE-2.0
96be832e2SEd Tanous 
106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software
116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS,
126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136be832e2SEd Tanous See the License for the specific language governing permissions and
146be832e2SEd Tanous limitations under the License.
1508777fb0SLewanczyk, Dawid */
1608777fb0SLewanczyk, Dawid #pragma once
1708777fb0SLewanczyk, Dawid 
183ccb3adbSEd Tanous #include "app.hpp"
193ccb3adbSEd Tanous #include "dbus_singleton.hpp"
207a1dbc48SGeorge Liu #include "dbus_utility.hpp"
21539d8c6bSEd Tanous #include "generated/enums/redundancy.hpp"
22aaf08ac7SMatt Simmering #include "generated/enums/resource.hpp"
233ccb3adbSEd Tanous #include "query.hpp"
243ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
2550ebd4afSEd Tanous #include "str_utility.hpp"
263ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
273ccb3adbSEd Tanous #include "utils/json_utils.hpp"
283ccb3adbSEd Tanous #include "utils/query_param.hpp"
291516c21bSJanet Adkins #include "utils/sensor_utils.hpp"
300ec8b83dSEd Tanous 
31e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
32ef4c65b7SEd Tanous #include <boost/url/format.hpp>
331e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp>
3486d89ed7SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
351214b7e7SGunnar Mills 
367a1dbc48SGeorge Liu #include <array>
371214b7e7SGunnar Mills #include <cmath>
38fe04d49cSNan Zhou #include <iterator>
39283860f5SEd Tanous #include <limits>
40fe04d49cSNan Zhou #include <map>
413544d2a7SEd Tanous #include <ranges>
42fe04d49cSNan Zhou #include <set>
4318f8f608SEd Tanous #include <string>
447a1dbc48SGeorge Liu #include <string_view>
45b5a76932SEd Tanous #include <utility>
46abf2add6SEd Tanous #include <variant>
4708777fb0SLewanczyk, Dawid 
481abe55efSEd Tanous namespace redfish
491abe55efSEd Tanous {
5008777fb0SLewanczyk, Dawid 
51a0ec28b6SAdrian Ambrożewicz namespace sensors
52a0ec28b6SAdrian Ambrożewicz {
53a0ec28b6SAdrian Ambrożewicz 
5402da7c5aSEd Tanous // clang-format off
55a0ec28b6SAdrian Ambrożewicz namespace dbus
56a0ec28b6SAdrian Ambrożewicz {
57cf9e417dSEd Tanous constexpr auto powerPaths = std::to_array<std::string_view>({
5802da7c5aSEd Tanous     "/xyz/openbmc_project/sensors/voltage",
5902da7c5aSEd Tanous     "/xyz/openbmc_project/sensors/power"
6002da7c5aSEd Tanous });
61c2bf7f99SWludzik, Jozef 
6225b54dbaSEd Tanous constexpr auto getSensorPaths(){
6325b54dbaSEd Tanous     if constexpr(BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM){
6425b54dbaSEd Tanous     return std::to_array<std::string_view>({
6502da7c5aSEd Tanous         "/xyz/openbmc_project/sensors/power",
66a0ec28b6SAdrian Ambrożewicz         "/xyz/openbmc_project/sensors/current",
677088690cSBasheer Ahmed Muddebihal         "/xyz/openbmc_project/sensors/airflow",
685deabed9SGunnar Mills         "/xyz/openbmc_project/sensors/humidity",
69e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/voltage",
70e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/fan_tach",
71e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/temperature",
72e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/fan_pwm",
73e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/altitude",
74e8204933SGeorge Liu         "/xyz/openbmc_project/sensors/energy",
7525b54dbaSEd Tanous         "/xyz/openbmc_project/sensors/utilization"});
7625b54dbaSEd Tanous     } else {
7725b54dbaSEd Tanous       return  std::to_array<std::string_view>({"/xyz/openbmc_project/sensors/power",
7825b54dbaSEd Tanous         "/xyz/openbmc_project/sensors/current",
7925b54dbaSEd Tanous         "/xyz/openbmc_project/sensors/airflow",
8025b54dbaSEd Tanous         "/xyz/openbmc_project/sensors/humidity",
8125b54dbaSEd Tanous         "/xyz/openbmc_project/sensors/utilization"});
8225b54dbaSEd Tanous }
8325b54dbaSEd Tanous }
8425b54dbaSEd Tanous 
8525b54dbaSEd Tanous constexpr auto sensorPaths = getSensorPaths();
8602da7c5aSEd Tanous 
87cf9e417dSEd Tanous constexpr auto thermalPaths = std::to_array<std::string_view>({
8802da7c5aSEd Tanous     "/xyz/openbmc_project/sensors/fan_tach",
89a0ec28b6SAdrian Ambrożewicz     "/xyz/openbmc_project/sensors/temperature",
9002da7c5aSEd Tanous     "/xyz/openbmc_project/sensors/fan_pwm"
9102da7c5aSEd Tanous });
9202da7c5aSEd Tanous 
93c2bf7f99SWludzik, Jozef } // namespace dbus
9402da7c5aSEd Tanous // clang-format on
9502da7c5aSEd Tanous 
960c728b42SJanet Adkins constexpr std::string_view powerNodeStr = sensor_utils::chassisSubNodeToString(
970c728b42SJanet Adkins     sensor_utils::ChassisSubNode::powerNode);
980c728b42SJanet Adkins constexpr std::string_view sensorsNodeStr =
990c728b42SJanet Adkins     sensor_utils::chassisSubNodeToString(
1000c728b42SJanet Adkins         sensor_utils::ChassisSubNode::sensorsNode);
1010c728b42SJanet Adkins constexpr std::string_view thermalNodeStr =
1020c728b42SJanet Adkins     sensor_utils::chassisSubNodeToString(
1030c728b42SJanet Adkins         sensor_utils::ChassisSubNode::thermalNode);
1040c728b42SJanet Adkins 
105cf9e417dSEd Tanous using sensorPair =
106cf9e417dSEd Tanous     std::pair<std::string_view, std::span<const std::string_view>>;
10702da7c5aSEd Tanous static constexpr std::array<sensorPair, 3> paths = {
1080c728b42SJanet Adkins     {{sensors::powerNodeStr, dbus::powerPaths},
1090c728b42SJanet Adkins      {sensors::sensorsNodeStr, dbus::sensorPaths},
1100c728b42SJanet Adkins      {sensors::thermalNodeStr, dbus::thermalPaths}}};
111c2bf7f99SWludzik, Jozef 
112a0ec28b6SAdrian Ambrożewicz } // namespace sensors
113a0ec28b6SAdrian Ambrożewicz 
11408777fb0SLewanczyk, Dawid /**
115588c3f0dSKowalski, Kamil  * SensorsAsyncResp
11608777fb0SLewanczyk, Dawid  * Gathers data needed for response processing after async calls are done
11708777fb0SLewanczyk, Dawid  */
1181abe55efSEd Tanous class SensorsAsyncResp
1191abe55efSEd Tanous {
12008777fb0SLewanczyk, Dawid   public:
121a0ec28b6SAdrian Ambrożewicz     using DataCompleteCb = std::function<void(
122a0ec28b6SAdrian Ambrożewicz         const boost::beast::http::status status,
123fe04d49cSNan Zhou         const std::map<std::string, std::string>& uriToDbus)>;
124a0ec28b6SAdrian Ambrożewicz 
125a0ec28b6SAdrian Ambrożewicz     struct SensorData
126a0ec28b6SAdrian Ambrożewicz     {
127f836c1d8SEd Tanous         std::string name;
128a0ec28b6SAdrian Ambrożewicz         std::string uri;
129f836c1d8SEd Tanous         std::string dbusPath;
130a0ec28b6SAdrian Ambrożewicz     };
131a0ec28b6SAdrian Ambrożewicz 
1328a592810SEd Tanous     SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
1338d1b46d7Szhanghch05                      const std::string& chassisIdIn,
134cf9e417dSEd Tanous                      std::span<const std::string_view> typesIn,
13502da7c5aSEd Tanous                      std::string_view subNode) :
136bd79bce8SPatrick Williams         asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
137bd79bce8SPatrick Williams         chassisSubNode(subNode), efficientExpand(false)
1381214b7e7SGunnar Mills     {}
13908777fb0SLewanczyk, Dawid 
140a0ec28b6SAdrian Ambrożewicz     // Store extra data about sensor mapping and return it in callback
1418a592810SEd Tanous     SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
1428d1b46d7Szhanghch05                      const std::string& chassisIdIn,
143cf9e417dSEd Tanous                      std::span<const std::string_view> typesIn,
14402da7c5aSEd Tanous                      std::string_view subNode,
145a0ec28b6SAdrian Ambrożewicz                      DataCompleteCb&& creationComplete) :
146bd79bce8SPatrick Williams         asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
147bd79bce8SPatrick Williams         chassisSubNode(subNode), efficientExpand(false),
148bd79bce8SPatrick Williams         metadata{std::vector<SensorData>()},
149a0ec28b6SAdrian Ambrożewicz         dataComplete{std::move(creationComplete)}
150a0ec28b6SAdrian Ambrożewicz     {}
151a0ec28b6SAdrian Ambrożewicz 
152928fefb9SNan Zhou     // sensor collections expand
1538a592810SEd Tanous     SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
154928fefb9SNan Zhou                      const std::string& chassisIdIn,
155cf9e417dSEd Tanous                      std::span<const std::string_view> typesIn,
1568a592810SEd Tanous                      const std::string_view& subNode, bool efficientExpandIn) :
157bd79bce8SPatrick Williams         asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
158bd79bce8SPatrick Williams         chassisSubNode(subNode), efficientExpand(efficientExpandIn)
159928fefb9SNan Zhou     {}
160928fefb9SNan Zhou 
1611abe55efSEd Tanous     ~SensorsAsyncResp()
1621abe55efSEd Tanous     {
1638d1b46d7Szhanghch05         if (asyncResp->res.result() ==
1648d1b46d7Szhanghch05             boost::beast::http::status::internal_server_error)
1651abe55efSEd Tanous         {
1661abe55efSEd Tanous             // Reset the json object to clear out any data that made it in
1671abe55efSEd Tanous             // before the error happened todo(ed) handle error condition with
1681abe55efSEd Tanous             // proper code
1698d1b46d7Szhanghch05             asyncResp->res.jsonValue = nlohmann::json::object();
17008777fb0SLewanczyk, Dawid         }
171a0ec28b6SAdrian Ambrożewicz 
172a0ec28b6SAdrian Ambrożewicz         if (dataComplete && metadata)
173a0ec28b6SAdrian Ambrożewicz         {
174fe04d49cSNan Zhou             std::map<std::string, std::string> map;
1758d1b46d7Szhanghch05             if (asyncResp->res.result() == boost::beast::http::status::ok)
176a0ec28b6SAdrian Ambrożewicz             {
177a0ec28b6SAdrian Ambrożewicz                 for (auto& sensor : *metadata)
178a0ec28b6SAdrian Ambrożewicz                 {
179c1d019a6SEd Tanous                     map.emplace(sensor.uri, sensor.dbusPath);
180a0ec28b6SAdrian Ambrożewicz                 }
181a0ec28b6SAdrian Ambrożewicz             }
1828d1b46d7Szhanghch05             dataComplete(asyncResp->res.result(), map);
183a0ec28b6SAdrian Ambrożewicz         }
18408777fb0SLewanczyk, Dawid     }
185588c3f0dSKowalski, Kamil 
186ecd6a3a2SEd Tanous     SensorsAsyncResp(const SensorsAsyncResp&) = delete;
187ecd6a3a2SEd Tanous     SensorsAsyncResp(SensorsAsyncResp&&) = delete;
188ecd6a3a2SEd Tanous     SensorsAsyncResp& operator=(const SensorsAsyncResp&) = delete;
189ecd6a3a2SEd Tanous     SensorsAsyncResp& operator=(SensorsAsyncResp&&) = delete;
190ecd6a3a2SEd Tanous 
191a0ec28b6SAdrian Ambrożewicz     void addMetadata(const nlohmann::json& sensorObject,
192c1d019a6SEd Tanous                      const std::string& dbusPath)
193a0ec28b6SAdrian Ambrożewicz     {
194a0ec28b6SAdrian Ambrożewicz         if (metadata)
195a0ec28b6SAdrian Ambrożewicz         {
196c1d019a6SEd Tanous             metadata->emplace_back(SensorData{
197c1d019a6SEd Tanous                 sensorObject["Name"], sensorObject["@odata.id"], dbusPath});
198a0ec28b6SAdrian Ambrożewicz         }
199a0ec28b6SAdrian Ambrożewicz     }
200a0ec28b6SAdrian Ambrożewicz 
201a0ec28b6SAdrian Ambrożewicz     void updateUri(const std::string& name, const std::string& uri)
202a0ec28b6SAdrian Ambrożewicz     {
203a0ec28b6SAdrian Ambrożewicz         if (metadata)
204a0ec28b6SAdrian Ambrożewicz         {
205a0ec28b6SAdrian Ambrożewicz             for (auto& sensor : *metadata)
206a0ec28b6SAdrian Ambrożewicz             {
207a0ec28b6SAdrian Ambrożewicz                 if (sensor.name == name)
208a0ec28b6SAdrian Ambrożewicz                 {
209a0ec28b6SAdrian Ambrożewicz                     sensor.uri = uri;
210a0ec28b6SAdrian Ambrożewicz                 }
211a0ec28b6SAdrian Ambrożewicz             }
212a0ec28b6SAdrian Ambrożewicz         }
213a0ec28b6SAdrian Ambrożewicz     }
214a0ec28b6SAdrian Ambrożewicz 
2158d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
216a0ec28b6SAdrian Ambrożewicz     const std::string chassisId;
217cf9e417dSEd Tanous     const std::span<const std::string_view> types;
218a0ec28b6SAdrian Ambrożewicz     const std::string chassisSubNode;
219928fefb9SNan Zhou     const bool efficientExpand;
220a0ec28b6SAdrian Ambrożewicz 
221a0ec28b6SAdrian Ambrożewicz   private:
222a0ec28b6SAdrian Ambrożewicz     std::optional<std::vector<SensorData>> metadata;
223a0ec28b6SAdrian Ambrożewicz     DataCompleteCb dataComplete;
22408777fb0SLewanczyk, Dawid };
22508777fb0SLewanczyk, Dawid 
226c9563608SJanet Adkins using InventoryItem = sensor_utils::InventoryItem;
227adc4f0dbSShawn McCarney 
228adc4f0dbSShawn McCarney /**
229413961deSRichard Marian Thomaiyar  * @brief Get objects with connection necessary for sensors
230588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp Pointer to object holding response data
23108777fb0SLewanczyk, Dawid  * @param sensorNames Sensors retrieved from chassis
23208777fb0SLewanczyk, Dawid  * @param callback Callback for processing gathered connections
23308777fb0SLewanczyk, Dawid  */
23408777fb0SLewanczyk, Dawid template <typename Callback>
235413961deSRichard Marian Thomaiyar void getObjectsWithConnection(
23681ce609eSEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
237fe04d49cSNan Zhou     const std::shared_ptr<std::set<std::string>>& sensorNames,
2381abe55efSEd Tanous     Callback&& callback)
2391abe55efSEd Tanous {
24062598e31SEd Tanous     BMCWEB_LOG_DEBUG("getObjectsWithConnection enter");
24103b5bae3SJames Feist     const std::string path = "/xyz/openbmc_project/sensors";
242e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
24308777fb0SLewanczyk, Dawid         "xyz.openbmc_project.Sensor.Value"};
24408777fb0SLewanczyk, Dawid 
245e99073f5SGeorge Liu     // Make call to ObjectMapper to find all sensors objects
246e99073f5SGeorge Liu     dbus::utility::getSubTree(
247e99073f5SGeorge Liu         path, 2, interfaces,
2488cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), sensorsAsyncResp,
249e99073f5SGeorge Liu          sensorNames](const boost::system::error_code& ec,
250002d39b4SEd Tanous                       const dbus::utility::MapperGetSubTreeResponse& subtree) {
251e99073f5SGeorge Liu             // Response handler for parsing objects subtree
25262598e31SEd Tanous             BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler enter");
2531abe55efSEd Tanous             if (ec)
2541abe55efSEd Tanous             {
2558d1b46d7Szhanghch05                 messages::internalError(sensorsAsyncResp->asyncResp->res);
25662598e31SEd Tanous                 BMCWEB_LOG_ERROR(
25762598e31SEd Tanous                     "getObjectsWithConnection resp_handler: Dbus error {}", ec);
25808777fb0SLewanczyk, Dawid                 return;
25908777fb0SLewanczyk, Dawid             }
26008777fb0SLewanczyk, Dawid 
26162598e31SEd Tanous             BMCWEB_LOG_DEBUG("Found {} subtrees", subtree.size());
26208777fb0SLewanczyk, Dawid 
263bd79bce8SPatrick Williams             // Make unique list of connections only for requested sensor types
264bd79bce8SPatrick Williams             // and found in the chassis
265fe04d49cSNan Zhou             std::set<std::string> connections;
266413961deSRichard Marian Thomaiyar             std::set<std::pair<std::string, std::string>> objectsWithConnection;
26708777fb0SLewanczyk, Dawid 
26862598e31SEd Tanous             BMCWEB_LOG_DEBUG("sensorNames list count: {}", sensorNames->size());
26949c53ac9SJohnathan Mantey             for (const std::string& tsensor : *sensorNames)
2701abe55efSEd Tanous             {
27162598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Sensor to find: {}", tsensor);
27208777fb0SLewanczyk, Dawid             }
27308777fb0SLewanczyk, Dawid 
274bd79bce8SPatrick Williams             for (const std::pair<std::string,
275bd79bce8SPatrick Williams                                  std::vector<std::pair<
276bd79bce8SPatrick Williams                                      std::string, std::vector<std::string>>>>&
2771abe55efSEd Tanous                      object : subtree)
2781abe55efSEd Tanous             {
27949c53ac9SJohnathan Mantey                 if (sensorNames->find(object.first) != sensorNames->end())
2801abe55efSEd Tanous                 {
28149c53ac9SJohnathan Mantey                     for (const std::pair<std::string, std::vector<std::string>>&
2821abe55efSEd Tanous                              objData : object.second)
2831abe55efSEd Tanous                     {
284bd79bce8SPatrick Williams                         BMCWEB_LOG_DEBUG("Adding connection: {}",
285bd79bce8SPatrick Williams                                          objData.first);
28608777fb0SLewanczyk, Dawid                         connections.insert(objData.first);
287de629b6eSShawn McCarney                         objectsWithConnection.insert(
288de629b6eSShawn McCarney                             std::make_pair(object.first, objData.first));
28908777fb0SLewanczyk, Dawid                     }
29008777fb0SLewanczyk, Dawid                 }
29108777fb0SLewanczyk, Dawid             }
29262598e31SEd Tanous             BMCWEB_LOG_DEBUG("Found {} connections", connections.size());
293413961deSRichard Marian Thomaiyar             callback(std::move(connections), std::move(objectsWithConnection));
29462598e31SEd Tanous             BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler exit");
295e99073f5SGeorge Liu         });
29662598e31SEd Tanous     BMCWEB_LOG_DEBUG("getObjectsWithConnection exit");
297413961deSRichard Marian Thomaiyar }
298413961deSRichard Marian Thomaiyar 
299413961deSRichard Marian Thomaiyar /**
300413961deSRichard Marian Thomaiyar  * @brief Create connections necessary for sensors
301413961deSRichard Marian Thomaiyar  * @param SensorsAsyncResp Pointer to object holding response data
302413961deSRichard Marian Thomaiyar  * @param sensorNames Sensors retrieved from chassis
303413961deSRichard Marian Thomaiyar  * @param callback Callback for processing gathered connections
304413961deSRichard Marian Thomaiyar  */
305413961deSRichard Marian Thomaiyar template <typename Callback>
306fe04d49cSNan Zhou void getConnections(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
307fe04d49cSNan Zhou                     const std::shared_ptr<std::set<std::string>> sensorNames,
308413961deSRichard Marian Thomaiyar                     Callback&& callback)
309413961deSRichard Marian Thomaiyar {
310413961deSRichard Marian Thomaiyar     auto objectsWithConnectionCb =
3118cb2c024SEd Tanous         [callback = std::forward<Callback>(callback)](
3128cb2c024SEd Tanous             const std::set<std::string>& connections,
313413961deSRichard Marian Thomaiyar             const std::set<std::pair<std::string, std::string>>&
3143174e4dfSEd Tanous             /*objectsWithConnection*/) { callback(connections); };
31581ce609eSEd Tanous     getObjectsWithConnection(sensorsAsyncResp, sensorNames,
316413961deSRichard Marian Thomaiyar                              std::move(objectsWithConnectionCb));
31708777fb0SLewanczyk, Dawid }
31808777fb0SLewanczyk, Dawid 
31908777fb0SLewanczyk, Dawid /**
32049c53ac9SJohnathan Mantey  * @brief Shrinks the list of sensors for processing
32149c53ac9SJohnathan Mantey  * @param SensorsAysncResp  The class holding the Redfish response
32249c53ac9SJohnathan Mantey  * @param allSensors  A list of all the sensors associated to the
32349c53ac9SJohnathan Mantey  * chassis element (i.e. baseboard, front panel, etc...)
32449c53ac9SJohnathan Mantey  * @param activeSensors A list that is a reduction of the incoming
32549c53ac9SJohnathan Mantey  * allSensors list.  Eliminate Thermal sensors when a Power request is
32649c53ac9SJohnathan Mantey  * made, and eliminate Power sensors when a Thermal request is made.
32749c53ac9SJohnathan Mantey  */
32823a21a1cSEd Tanous inline void reduceSensorList(
3297f1cc26dSEd Tanous     crow::Response& res, std::string_view chassisSubNode,
330cf9e417dSEd Tanous     std::span<const std::string_view> sensorTypes,
33149c53ac9SJohnathan Mantey     const std::vector<std::string>* allSensors,
332fe04d49cSNan Zhou     const std::shared_ptr<std::set<std::string>>& activeSensors)
33349c53ac9SJohnathan Mantey {
33449c53ac9SJohnathan Mantey     if ((allSensors == nullptr) || (activeSensors == nullptr))
33549c53ac9SJohnathan Mantey     {
3367f1cc26dSEd Tanous         messages::resourceNotFound(res, chassisSubNode,
3370c728b42SJanet Adkins                                    chassisSubNode == sensors::thermalNodeStr
338a0ec28b6SAdrian Ambrożewicz                                        ? "Temperatures"
33949c53ac9SJohnathan Mantey                                        : "Voltages");
34049c53ac9SJohnathan Mantey 
34149c53ac9SJohnathan Mantey         return;
34249c53ac9SJohnathan Mantey     }
34349c53ac9SJohnathan Mantey     if (allSensors->empty())
34449c53ac9SJohnathan Mantey     {
34549c53ac9SJohnathan Mantey         // Nothing to do, the activeSensors object is also empty
34649c53ac9SJohnathan Mantey         return;
34749c53ac9SJohnathan Mantey     }
34849c53ac9SJohnathan Mantey 
3497f1cc26dSEd Tanous     for (std::string_view type : sensorTypes)
35049c53ac9SJohnathan Mantey     {
35149c53ac9SJohnathan Mantey         for (const std::string& sensor : *allSensors)
35249c53ac9SJohnathan Mantey         {
35311ba3979SEd Tanous             if (sensor.starts_with(type))
35449c53ac9SJohnathan Mantey             {
35549c53ac9SJohnathan Mantey                 activeSensors->emplace(sensor);
35649c53ac9SJohnathan Mantey             }
35749c53ac9SJohnathan Mantey         }
35849c53ac9SJohnathan Mantey     }
35949c53ac9SJohnathan Mantey }
36049c53ac9SJohnathan Mantey 
3617f1cc26dSEd Tanous /*
3627f1cc26dSEd Tanous  *Populates the top level collection for a given subnode.  Populates
3637f1cc26dSEd Tanous  *SensorCollection, Power, or Thermal schemas.
3647f1cc26dSEd Tanous  *
3657f1cc26dSEd Tanous  * */
3667f1cc26dSEd Tanous inline void populateChassisNode(nlohmann::json& jsonValue,
3677f1cc26dSEd Tanous                                 std::string_view chassisSubNode)
3687f1cc26dSEd Tanous {
3690c728b42SJanet Adkins     if (chassisSubNode == sensors::powerNodeStr)
3707f1cc26dSEd Tanous     {
3717f1cc26dSEd Tanous         jsonValue["@odata.type"] = "#Power.v1_5_2.Power";
3727f1cc26dSEd Tanous     }
3730c728b42SJanet Adkins     else if (chassisSubNode == sensors::thermalNodeStr)
3747f1cc26dSEd Tanous     {
3757f1cc26dSEd Tanous         jsonValue["@odata.type"] = "#Thermal.v1_4_0.Thermal";
3767f1cc26dSEd Tanous         jsonValue["Fans"] = nlohmann::json::array();
3777f1cc26dSEd Tanous         jsonValue["Temperatures"] = nlohmann::json::array();
3787f1cc26dSEd Tanous     }
3790c728b42SJanet Adkins     else if (chassisSubNode == sensors::sensorsNodeStr)
3807f1cc26dSEd Tanous     {
3817f1cc26dSEd Tanous         jsonValue["@odata.type"] = "#SensorCollection.SensorCollection";
3827f1cc26dSEd Tanous         jsonValue["Description"] = "Collection of Sensors for this Chassis";
3837f1cc26dSEd Tanous         jsonValue["Members"] = nlohmann::json::array();
3847f1cc26dSEd Tanous         jsonValue["Members@odata.count"] = 0;
3857f1cc26dSEd Tanous     }
3867f1cc26dSEd Tanous 
3870c728b42SJanet Adkins     if (chassisSubNode != sensors::sensorsNodeStr)
3887f1cc26dSEd Tanous     {
3897f1cc26dSEd Tanous         jsonValue["Id"] = chassisSubNode;
3907f1cc26dSEd Tanous     }
3917f1cc26dSEd Tanous     jsonValue["Name"] = chassisSubNode;
3927f1cc26dSEd Tanous }
3937f1cc26dSEd Tanous 
39449c53ac9SJohnathan Mantey /**
39508777fb0SLewanczyk, Dawid  * @brief Retrieves requested chassis sensors and redundancy data from DBus .
396588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
39708777fb0SLewanczyk, Dawid  * @param callback  Callback for next step in gathered sensor processing
39808777fb0SLewanczyk, Dawid  */
39908777fb0SLewanczyk, Dawid template <typename Callback>
4007f1cc26dSEd Tanous void getChassis(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4017f1cc26dSEd Tanous                 std::string_view chassisId, std::string_view chassisSubNode,
402cf9e417dSEd Tanous                 std::span<const std::string_view> sensorTypes,
403cf9e417dSEd Tanous                 Callback&& callback)
4041abe55efSEd Tanous {
40562598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassis enter");
4067a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
40749c53ac9SJohnathan Mantey         "xyz.openbmc_project.Inventory.Item.Board",
408adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Item.Chassis"};
4097a1dbc48SGeorge Liu 
4107a1dbc48SGeorge Liu     // Get the Chassis Collection
4117a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
4127a1dbc48SGeorge Liu         "/xyz/openbmc_project/inventory", 0, interfaces,
4138cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), asyncResp,
4147f1cc26dSEd Tanous          chassisIdStr{std::string(chassisId)},
4154e0d8789SEd Tanous          chassisSubNode{std::string(chassisSubNode)},
4164e0d8789SEd Tanous          sensorTypes](const boost::system::error_code& ec,
4174e0d8789SEd Tanous                       const dbus::utility::MapperGetSubTreePathsResponse&
4184e0d8789SEd Tanous                           chassisPaths) mutable {
41962598e31SEd Tanous             BMCWEB_LOG_DEBUG("getChassis respHandler enter");
4201abe55efSEd Tanous             if (ec)
4211abe55efSEd Tanous             {
42262598e31SEd Tanous                 BMCWEB_LOG_ERROR("getChassis respHandler DBUS error: {}", ec);
4237f1cc26dSEd Tanous                 messages::internalError(asyncResp->res);
42408777fb0SLewanczyk, Dawid                 return;
42508777fb0SLewanczyk, Dawid             }
42649c53ac9SJohnathan Mantey             const std::string* chassisPath = nullptr;
42749c53ac9SJohnathan Mantey             for (const std::string& chassis : chassisPaths)
4281abe55efSEd Tanous             {
42928aa8de5SGeorge Liu                 sdbusplus::message::object_path path(chassis);
430f8fe53e7SEd Tanous                 std::string chassisName = path.filename();
43128aa8de5SGeorge Liu                 if (chassisName.empty())
4321abe55efSEd Tanous                 {
43362598e31SEd Tanous                     BMCWEB_LOG_ERROR("Failed to find '/' in {}", chassis);
434daf36e2eSEd Tanous                     continue;
435daf36e2eSEd Tanous                 }
4367f1cc26dSEd Tanous                 if (chassisName == chassisIdStr)
4371abe55efSEd Tanous                 {
43849c53ac9SJohnathan Mantey                     chassisPath = &chassis;
43949c53ac9SJohnathan Mantey                     break;
440daf36e2eSEd Tanous                 }
44149c53ac9SJohnathan Mantey             }
44249c53ac9SJohnathan Mantey             if (chassisPath == nullptr)
4431abe55efSEd Tanous             {
444bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res, "Chassis",
445bd79bce8SPatrick Williams                                            chassisIdStr);
44649c53ac9SJohnathan Mantey                 return;
4471abe55efSEd Tanous             }
4487f1cc26dSEd Tanous             populateChassisNode(asyncResp->res.jsonValue, chassisSubNode);
44908777fb0SLewanczyk, Dawid 
450ef4c65b7SEd Tanous             asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
451ef4c65b7SEd Tanous                 "/redfish/v1/Chassis/{}/{}", chassisIdStr, chassisSubNode);
45295a3ecadSAnthony Wilson 
4538fb49dd6SShawn McCarney             // Get the list of all sensors for this Chassis element
4548fb49dd6SShawn McCarney             std::string sensorPath = *chassisPath + "/all_sensors";
4556c3e9451SGeorge Liu             dbus::utility::getAssociationEndPoints(
4564e0d8789SEd Tanous                 sensorPath, [asyncResp, chassisSubNode, sensorTypes,
4574e0d8789SEd Tanous                              callback = std::forward<Callback>(callback)](
4588b24275dSEd Tanous                                 const boost::system::error_code& ec2,
4594e0d8789SEd Tanous                                 const dbus::utility::MapperEndPoints&
4604e0d8789SEd Tanous                                     nodeSensorList) mutable {
4618b24275dSEd Tanous                     if (ec2)
46249c53ac9SJohnathan Mantey                     {
4638b24275dSEd Tanous                         if (ec2.value() != EBADR)
46449c53ac9SJohnathan Mantey                         {
4657f1cc26dSEd Tanous                             messages::internalError(asyncResp->res);
46649c53ac9SJohnathan Mantey                             return;
46749c53ac9SJohnathan Mantey                         }
46849c53ac9SJohnathan Mantey                     }
469bd79bce8SPatrick Williams                     const std::shared_ptr<std::set<std::string>>
470bd79bce8SPatrick Williams                         culledSensorList =
471fe04d49cSNan Zhou                             std::make_shared<std::set<std::string>>();
472bd79bce8SPatrick Williams                     reduceSensorList(asyncResp->res, chassisSubNode,
473bd79bce8SPatrick Williams                                      sensorTypes, &nodeSensorList,
474bd79bce8SPatrick Williams                                      culledSensorList);
475bd79bce8SPatrick Williams                     BMCWEB_LOG_DEBUG("Finishing with {}",
476bd79bce8SPatrick Williams                                      culledSensorList->size());
47749c53ac9SJohnathan Mantey                     callback(culledSensorList);
4781e1e598dSJonathan Doman                 });
4797a1dbc48SGeorge Liu         });
48062598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassis exit");
48108777fb0SLewanczyk, Dawid }
48208777fb0SLewanczyk, Dawid 
48308777fb0SLewanczyk, Dawid /**
4841d7c0054SEd Tanous  * @brief Builds a json sensor representation of a sensor.
4851d7c0054SEd Tanous  * @param sensorName  The name of the sensor to be built
4861d7c0054SEd Tanous  * @param sensorType  The type (temperature, fan_tach, etc) of the sensor to
4871d7c0054SEd Tanous  * build
4888ece0e45SEd Tanous  * @param chassisSubNode The subnode (thermal, sensor, etc) of the sensor
4891d7c0054SEd Tanous  * @param interfacesDict  A dictionary of the interfaces and properties of said
4901d7c0054SEd Tanous  * interfaces to be built from
4911d7c0054SEd Tanous  * @param sensorJson  The json object to fill
4921d7c0054SEd Tanous  * @param inventoryItem D-Bus inventory item associated with the sensor.  Will
4931d7c0054SEd Tanous  * be nullptr if no associated inventory item was found.
4941d7c0054SEd Tanous  */
4951d7c0054SEd Tanous inline void objectInterfacesToJson(
4961d7c0054SEd Tanous     const std::string& sensorName, const std::string& sensorType,
4970c728b42SJanet Adkins     const sensor_utils::ChassisSubNode chassisSubNode,
49880f79a40SMichael Shen     const dbus::utility::DBusInterfacesMap& interfacesDict,
4991d7c0054SEd Tanous     nlohmann::json& sensorJson, InventoryItem* inventoryItem)
5001d7c0054SEd Tanous {
5011d7c0054SEd Tanous     for (const auto& [interface, valuesDict] : interfacesDict)
5021d7c0054SEd Tanous     {
503c9563608SJanet Adkins         sensor_utils::objectPropertiesToJson(
504c9563608SJanet Adkins             sensorName, sensorType, chassisSubNode, valuesDict, sensorJson,
505c9563608SJanet Adkins             inventoryItem);
5061d7c0054SEd Tanous     }
50762598e31SEd Tanous     BMCWEB_LOG_DEBUG("Added sensor {}", sensorName);
5081d7c0054SEd Tanous }
5091d7c0054SEd Tanous 
510b5a76932SEd Tanous inline void populateFanRedundancy(
511b5a76932SEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
5128bd25ccdSJames Feist {
513e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
514e99073f5SGeorge Liu         "xyz.openbmc_project.Control.FanRedundancy"};
515e99073f5SGeorge Liu     dbus::utility::getSubTree(
516e99073f5SGeorge Liu         "/xyz/openbmc_project/control", 2, interfaces,
517b9d36b47SEd Tanous         [sensorsAsyncResp](
518e99073f5SGeorge Liu             const boost::system::error_code& ec,
519b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& resp) {
5208bd25ccdSJames Feist             if (ec)
5218bd25ccdSJames Feist             {
5228bd25ccdSJames Feist                 return; // don't have to have this interface
5238bd25ccdSJames Feist             }
5246c3e9451SGeorge Liu             for (const std::pair<std::string, dbus::utility::MapperServiceMap>&
525e278c18fSEd Tanous                      pathPair : resp)
5268bd25ccdSJames Feist             {
527e278c18fSEd Tanous                 const std::string& path = pathPair.first;
528bd79bce8SPatrick Williams                 const dbus::utility::MapperServiceMap& objDict =
529bd79bce8SPatrick Williams                     pathPair.second;
5308bd25ccdSJames Feist                 if (objDict.empty())
5318bd25ccdSJames Feist                 {
5328bd25ccdSJames Feist                     continue; // this should be impossible
5338bd25ccdSJames Feist                 }
5348bd25ccdSJames Feist 
5358bd25ccdSJames Feist                 const std::string& owner = objDict.begin()->first;
5366c3e9451SGeorge Liu                 dbus::utility::getAssociationEndPoints(
5376c3e9451SGeorge Liu                     path + "/chassis",
5386c3e9451SGeorge Liu                     [path, owner, sensorsAsyncResp](
5398b24275dSEd Tanous                         const boost::system::error_code& ec2,
5406c3e9451SGeorge Liu                         const dbus::utility::MapperEndPoints& endpoints) {
5418b24275dSEd Tanous                         if (ec2)
5428bd25ccdSJames Feist                         {
5438bd25ccdSJames Feist                             return; // if they don't have an association we
5448bd25ccdSJames Feist                                     // can't tell what chassis is
5458bd25ccdSJames Feist                         }
5463544d2a7SEd Tanous                         auto found = std::ranges::find_if(
547bd79bce8SPatrick Williams                             endpoints,
548bd79bce8SPatrick Williams                             [sensorsAsyncResp](const std::string& entry) {
549bd79bce8SPatrick Williams                                 return entry.find(
550bd79bce8SPatrick Williams                                            sensorsAsyncResp->chassisId) !=
5518bd25ccdSJames Feist                                        std::string::npos;
5528bd25ccdSJames Feist                             });
5538bd25ccdSJames Feist 
5541e1e598dSJonathan Doman                         if (found == endpoints.end())
5558bd25ccdSJames Feist                         {
5568bd25ccdSJames Feist                             return;
5578bd25ccdSJames Feist                         }
558*deae6a78SEd Tanous                         dbus::utility::getAllProperties(
55986d89ed7SKrzysztof Grobelny                             *crow::connections::systemBus, owner, path,
56086d89ed7SKrzysztof Grobelny                             "xyz.openbmc_project.Control.FanRedundancy",
5618bd25ccdSJames Feist                             [path, sensorsAsyncResp](
5628b24275dSEd Tanous                                 const boost::system::error_code& ec3,
56386d89ed7SKrzysztof Grobelny                                 const dbus::utility::DBusPropertiesMap& ret) {
5648b24275dSEd Tanous                                 if (ec3)
5658bd25ccdSJames Feist                                 {
5668bd25ccdSJames Feist                                     return; // don't have to have this
5678bd25ccdSJames Feist                                             // interface
5688bd25ccdSJames Feist                                 }
5698bd25ccdSJames Feist 
57086d89ed7SKrzysztof Grobelny                                 const uint8_t* allowedFailures = nullptr;
571bd79bce8SPatrick Williams                                 const std::vector<std::string>* collection =
572bd79bce8SPatrick Williams                                     nullptr;
57386d89ed7SKrzysztof Grobelny                                 const std::string* status = nullptr;
57486d89ed7SKrzysztof Grobelny 
575bd79bce8SPatrick Williams                                 const bool success =
576bd79bce8SPatrick Williams                                     sdbusplus::unpackPropertiesNoThrow(
57786d89ed7SKrzysztof Grobelny                                         dbus_utils::UnpackErrorPrinter(), ret,
578bd79bce8SPatrick Williams                                         "AllowedFailures", allowedFailures,
579bd79bce8SPatrick Williams                                         "Collection", collection, "Status",
580bd79bce8SPatrick Williams                                         status);
58186d89ed7SKrzysztof Grobelny 
58286d89ed7SKrzysztof Grobelny                                 if (!success)
58386d89ed7SKrzysztof Grobelny                                 {
58486d89ed7SKrzysztof Grobelny                                     messages::internalError(
58586d89ed7SKrzysztof Grobelny                                         sensorsAsyncResp->asyncResp->res);
58686d89ed7SKrzysztof Grobelny                                     return;
58786d89ed7SKrzysztof Grobelny                                 }
58886d89ed7SKrzysztof Grobelny 
589bd79bce8SPatrick Williams                                 if (allowedFailures == nullptr ||
590bd79bce8SPatrick Williams                                     collection == nullptr || status == nullptr)
5918bd25ccdSJames Feist                                 {
592bd79bce8SPatrick Williams                                     BMCWEB_LOG_ERROR(
593bd79bce8SPatrick Williams                                         "Invalid redundancy interface");
5948bd25ccdSJames Feist                                     messages::internalError(
5958d1b46d7Szhanghch05                                         sensorsAsyncResp->asyncResp->res);
5968bd25ccdSJames Feist                                     return;
5978bd25ccdSJames Feist                                 }
5988bd25ccdSJames Feist 
599bd79bce8SPatrick Williams                                 sdbusplus::message::object_path objectPath(
600bd79bce8SPatrick Williams                                     path);
60128aa8de5SGeorge Liu                                 std::string name = objectPath.filename();
60228aa8de5SGeorge Liu                                 if (name.empty())
6038bd25ccdSJames Feist                                 {
6048bd25ccdSJames Feist                                     // this should be impossible
6058bd25ccdSJames Feist                                     messages::internalError(
6068d1b46d7Szhanghch05                                         sensorsAsyncResp->asyncResp->res);
6078bd25ccdSJames Feist                                     return;
6088bd25ccdSJames Feist                                 }
60918f8f608SEd Tanous                                 std::ranges::replace(name, '_', ' ');
6108bd25ccdSJames Feist 
6118bd25ccdSJames Feist                                 std::string health;
6128bd25ccdSJames Feist 
61311ba3979SEd Tanous                                 if (status->ends_with("Full"))
6148bd25ccdSJames Feist                                 {
6158bd25ccdSJames Feist                                     health = "OK";
6168bd25ccdSJames Feist                                 }
61711ba3979SEd Tanous                                 else if (status->ends_with("Degraded"))
6188bd25ccdSJames Feist                                 {
6198bd25ccdSJames Feist                                     health = "Warning";
6208bd25ccdSJames Feist                                 }
6218bd25ccdSJames Feist                                 else
6228bd25ccdSJames Feist                                 {
6238bd25ccdSJames Feist                                     health = "Critical";
6248bd25ccdSJames Feist                                 }
6251476687dSEd Tanous                                 nlohmann::json::array_t redfishCollection;
6268bd25ccdSJames Feist                                 const auto& fanRedfish =
627bd79bce8SPatrick Williams                                     sensorsAsyncResp->asyncResp->res
628bd79bce8SPatrick Williams                                         .jsonValue["Fans"];
6298bd25ccdSJames Feist                                 for (const std::string& item : *collection)
6308bd25ccdSJames Feist                                 {
631bd79bce8SPatrick Williams                                     sdbusplus::message::object_path itemPath(
632bd79bce8SPatrick Williams                                         item);
6338a592810SEd Tanous                                     std::string itemName = itemPath.filename();
63428aa8de5SGeorge Liu                                     if (itemName.empty())
63528aa8de5SGeorge Liu                                     {
63628aa8de5SGeorge Liu                                         continue;
63728aa8de5SGeorge Liu                                     }
6388bd25ccdSJames Feist                                     /*
6398bd25ccdSJames Feist                                     todo(ed): merge patch that fixes the names
6408bd25ccdSJames Feist                                     std::replace(itemName.begin(),
6418bd25ccdSJames Feist                                                  itemName.end(), '_', ' ');*/
6423544d2a7SEd Tanous                                     auto schemaItem = std::ranges::find_if(
643bd79bce8SPatrick Williams                                         fanRedfish,
644bd79bce8SPatrick Williams                                         [itemName](const nlohmann::json& fan) {
6453e35c761SGeorge Liu                                             return fan["Name"] == itemName;
6468bd25ccdSJames Feist                                         });
6478bd25ccdSJames Feist                                     if (schemaItem != fanRedfish.end())
6488bd25ccdSJames Feist                                     {
6498a592810SEd Tanous                                         nlohmann::json::object_t collectionId;
6508a592810SEd Tanous                                         collectionId["@odata.id"] =
6511476687dSEd Tanous                                             (*schemaItem)["@odata.id"];
6521476687dSEd Tanous                                         redfishCollection.emplace_back(
6538a592810SEd Tanous                                             std::move(collectionId));
6548bd25ccdSJames Feist                                     }
6558bd25ccdSJames Feist                                     else
6568bd25ccdSJames Feist                                     {
657bd79bce8SPatrick Williams                                         BMCWEB_LOG_ERROR(
658bd79bce8SPatrick Williams                                             "failed to find fan in schema");
6598bd25ccdSJames Feist                                         messages::internalError(
6608d1b46d7Szhanghch05                                             sensorsAsyncResp->asyncResp->res);
6618bd25ccdSJames Feist                                         return;
6628bd25ccdSJames Feist                                     }
6638bd25ccdSJames Feist                                 }
6648bd25ccdSJames Feist 
665bd79bce8SPatrick Williams                                 size_t minNumNeeded =
666bd79bce8SPatrick Williams                                     collection->empty()
66726f6976fSEd Tanous                                         ? 0
668bd79bce8SPatrick Williams                                         : collection->size() - *allowedFailures;
669bd79bce8SPatrick Williams                                 nlohmann::json& jResp =
670bd79bce8SPatrick Williams                                     sensorsAsyncResp->asyncResp->res
6718bd25ccdSJames Feist                                         .jsonValue["Redundancy"];
6721476687dSEd Tanous 
6731476687dSEd Tanous                                 nlohmann::json::object_t redundancy;
674bd79bce8SPatrick Williams                                 boost::urls::url url = boost::urls::format(
675bd79bce8SPatrick Williams                                     "/redfish/v1/Chassis/{}/{}",
676ef4c65b7SEd Tanous                                     sensorsAsyncResp->chassisId,
677eddfc437SWilly Tu                                     sensorsAsyncResp->chassisSubNode);
678bd79bce8SPatrick Williams                                 url.set_fragment(
679bd79bce8SPatrick Williams                                     ("/Redundancy"_json_pointer / jResp.size())
680eddfc437SWilly Tu                                         .to_string());
681eddfc437SWilly Tu                                 redundancy["@odata.id"] = std::move(url);
682bd79bce8SPatrick Williams                                 redundancy["@odata.type"] =
683bd79bce8SPatrick Williams                                     "#Redundancy.v1_3_2.Redundancy";
6841476687dSEd Tanous                                 redundancy["MinNumNeeded"] = minNumNeeded;
685bd79bce8SPatrick Williams                                 redundancy["Mode"] =
686bd79bce8SPatrick Williams                                     redundancy::RedundancyType::NPlusM;
6871476687dSEd Tanous                                 redundancy["Name"] = name;
6881476687dSEd Tanous                                 redundancy["RedundancySet"] = redfishCollection;
6891476687dSEd Tanous                                 redundancy["Status"]["Health"] = health;
690bd79bce8SPatrick Williams                                 redundancy["Status"]["State"] =
691bd79bce8SPatrick Williams                                     resource::State::Enabled;
6921476687dSEd Tanous 
693b2ba3072SPatrick Williams                                 jResp.emplace_back(std::move(redundancy));
69486d89ed7SKrzysztof Grobelny                             });
6951e1e598dSJonathan Doman                     });
6968bd25ccdSJames Feist             }
697e99073f5SGeorge Liu         });
6988bd25ccdSJames Feist }
6998bd25ccdSJames Feist 
700b5a76932SEd Tanous inline void
70181ce609eSEd Tanous     sortJSONResponse(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
70249c53ac9SJohnathan Mantey {
7038d1b46d7Szhanghch05     nlohmann::json& response = sensorsAsyncResp->asyncResp->res.jsonValue;
70449c53ac9SJohnathan Mantey     std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
7050c728b42SJanet Adkins     if (sensorsAsyncResp->chassisSubNode == sensors::powerNodeStr)
70649c53ac9SJohnathan Mantey     {
70749c53ac9SJohnathan Mantey         sensorHeaders = {"Voltages", "PowerSupplies"};
70849c53ac9SJohnathan Mantey     }
70949c53ac9SJohnathan Mantey     for (const std::string& sensorGroup : sensorHeaders)
71049c53ac9SJohnathan Mantey     {
71149c53ac9SJohnathan Mantey         nlohmann::json::iterator entry = response.find(sensorGroup);
7124e196b9aSEd Tanous         if (entry == response.end())
71349c53ac9SJohnathan Mantey         {
7144e196b9aSEd Tanous             continue;
7154e196b9aSEd Tanous         }
7164e196b9aSEd Tanous         nlohmann::json::array_t* arr =
7174e196b9aSEd Tanous             entry->get_ptr<nlohmann::json::array_t*>();
7184e196b9aSEd Tanous         if (arr == nullptr)
7194e196b9aSEd Tanous         {
7204e196b9aSEd Tanous             continue;
7214e196b9aSEd Tanous         }
7224e196b9aSEd Tanous         json_util::sortJsonArrayByKey(*arr, "Name");
72349c53ac9SJohnathan Mantey 
72449c53ac9SJohnathan Mantey         // add the index counts to the end of each entry
72549c53ac9SJohnathan Mantey         size_t count = 0;
72649c53ac9SJohnathan Mantey         for (nlohmann::json& sensorJson : *entry)
72749c53ac9SJohnathan Mantey         {
72849c53ac9SJohnathan Mantey             nlohmann::json::iterator odata = sensorJson.find("@odata.id");
72949c53ac9SJohnathan Mantey             if (odata == sensorJson.end())
73049c53ac9SJohnathan Mantey             {
73149c53ac9SJohnathan Mantey                 continue;
73249c53ac9SJohnathan Mantey             }
73349c53ac9SJohnathan Mantey             std::string* value = odata->get_ptr<std::string*>();
73449c53ac9SJohnathan Mantey             if (value != nullptr)
73549c53ac9SJohnathan Mantey             {
736eddfc437SWilly Tu                 *value += "/" + std::to_string(count);
7373e35c761SGeorge Liu                 sensorJson["MemberId"] = std::to_string(count);
73849c53ac9SJohnathan Mantey                 count++;
73981ce609eSEd Tanous                 sensorsAsyncResp->updateUri(sensorJson["Name"], *value);
74049c53ac9SJohnathan Mantey             }
74149c53ac9SJohnathan Mantey         }
74249c53ac9SJohnathan Mantey     }
74349c53ac9SJohnathan Mantey }
74449c53ac9SJohnathan Mantey 
74508777fb0SLewanczyk, Dawid /**
746adc4f0dbSShawn McCarney  * @brief Finds the inventory item with the specified object path.
747adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
748adc4f0dbSShawn McCarney  * @param invItemObjPath D-Bus object path of inventory item.
749adc4f0dbSShawn McCarney  * @return Inventory item within vector, or nullptr if no match found.
7508fb49dd6SShawn McCarney  */
75123a21a1cSEd Tanous inline InventoryItem* findInventoryItem(
752b5a76932SEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
753adc4f0dbSShawn McCarney     const std::string& invItemObjPath)
7548fb49dd6SShawn McCarney {
755adc4f0dbSShawn McCarney     for (InventoryItem& inventoryItem : *inventoryItems)
7568fb49dd6SShawn McCarney     {
757adc4f0dbSShawn McCarney         if (inventoryItem.objectPath == invItemObjPath)
7588fb49dd6SShawn McCarney         {
759adc4f0dbSShawn McCarney             return &inventoryItem;
7608fb49dd6SShawn McCarney         }
7618fb49dd6SShawn McCarney     }
7628fb49dd6SShawn McCarney     return nullptr;
7638fb49dd6SShawn McCarney }
7648fb49dd6SShawn McCarney 
7658fb49dd6SShawn McCarney /**
766adc4f0dbSShawn McCarney  * @brief Finds the inventory item associated with the specified sensor.
767adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
768adc4f0dbSShawn McCarney  * @param sensorObjPath D-Bus object path of sensor.
769adc4f0dbSShawn McCarney  * @return Inventory item within vector, or nullptr if no match found.
7708fb49dd6SShawn McCarney  */
77123a21a1cSEd Tanous inline InventoryItem* findInventoryItemForSensor(
772b5a76932SEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
773adc4f0dbSShawn McCarney     const std::string& sensorObjPath)
774adc4f0dbSShawn McCarney {
775adc4f0dbSShawn McCarney     for (InventoryItem& inventoryItem : *inventoryItems)
776adc4f0dbSShawn McCarney     {
777db0d36efSEd Tanous         if (inventoryItem.sensors.contains(sensorObjPath))
778adc4f0dbSShawn McCarney         {
779adc4f0dbSShawn McCarney             return &inventoryItem;
780adc4f0dbSShawn McCarney         }
781adc4f0dbSShawn McCarney     }
782adc4f0dbSShawn McCarney     return nullptr;
783adc4f0dbSShawn McCarney }
784adc4f0dbSShawn McCarney 
785adc4f0dbSShawn McCarney /**
786d500549bSAnthony Wilson  * @brief Finds the inventory item associated with the specified led path.
787d500549bSAnthony Wilson  * @param inventoryItems D-Bus inventory items associated with sensors.
788d500549bSAnthony Wilson  * @param ledObjPath D-Bus object path of led.
789d500549bSAnthony Wilson  * @return Inventory item within vector, or nullptr if no match found.
790d500549bSAnthony Wilson  */
791bd79bce8SPatrick Williams inline InventoryItem* findInventoryItemForLed(
792bd79bce8SPatrick Williams     std::vector<InventoryItem>& inventoryItems, const std::string& ledObjPath)
793d500549bSAnthony Wilson {
794d500549bSAnthony Wilson     for (InventoryItem& inventoryItem : inventoryItems)
795d500549bSAnthony Wilson     {
796d500549bSAnthony Wilson         if (inventoryItem.ledObjectPath == ledObjPath)
797d500549bSAnthony Wilson         {
798d500549bSAnthony Wilson             return &inventoryItem;
799d500549bSAnthony Wilson         }
800d500549bSAnthony Wilson     }
801d500549bSAnthony Wilson     return nullptr;
802d500549bSAnthony Wilson }
803d500549bSAnthony Wilson 
804d500549bSAnthony Wilson /**
805adc4f0dbSShawn McCarney  * @brief Adds inventory item and associated sensor to specified vector.
806adc4f0dbSShawn McCarney  *
807adc4f0dbSShawn McCarney  * Adds a new InventoryItem to the vector if necessary.  Searches for an
808adc4f0dbSShawn McCarney  * existing InventoryItem with the specified object path.  If not found, one is
809adc4f0dbSShawn McCarney  * added to the vector.
810adc4f0dbSShawn McCarney  *
811adc4f0dbSShawn McCarney  * Next, the specified sensor is added to the set of sensors associated with the
812adc4f0dbSShawn McCarney  * InventoryItem.
813adc4f0dbSShawn McCarney  *
814adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
815adc4f0dbSShawn McCarney  * @param invItemObjPath D-Bus object path of inventory item.
816adc4f0dbSShawn McCarney  * @param sensorObjPath D-Bus object path of sensor
817adc4f0dbSShawn McCarney  */
818b5a76932SEd Tanous inline void addInventoryItem(
819b5a76932SEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
820b5a76932SEd Tanous     const std::string& invItemObjPath, const std::string& sensorObjPath)
821adc4f0dbSShawn McCarney {
822adc4f0dbSShawn McCarney     // Look for inventory item in vector
823bd79bce8SPatrick Williams     InventoryItem* inventoryItem =
824bd79bce8SPatrick Williams         findInventoryItem(inventoryItems, invItemObjPath);
825adc4f0dbSShawn McCarney 
826adc4f0dbSShawn McCarney     // If inventory item doesn't exist in vector, add it
827adc4f0dbSShawn McCarney     if (inventoryItem == nullptr)
828adc4f0dbSShawn McCarney     {
829adc4f0dbSShawn McCarney         inventoryItems->emplace_back(invItemObjPath);
830adc4f0dbSShawn McCarney         inventoryItem = &(inventoryItems->back());
831adc4f0dbSShawn McCarney     }
832adc4f0dbSShawn McCarney 
833adc4f0dbSShawn McCarney     // Add sensor to set of sensors associated with inventory item
834adc4f0dbSShawn McCarney     inventoryItem->sensors.emplace(sensorObjPath);
835adc4f0dbSShawn McCarney }
836adc4f0dbSShawn McCarney 
837adc4f0dbSShawn McCarney /**
838adc4f0dbSShawn McCarney  * @brief Stores D-Bus data in the specified inventory item.
839adc4f0dbSShawn McCarney  *
840adc4f0dbSShawn McCarney  * Finds D-Bus data in the specified map of interfaces.  Stores the data in the
841adc4f0dbSShawn McCarney  * specified InventoryItem.
842adc4f0dbSShawn McCarney  *
843adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
844adc4f0dbSShawn McCarney  * response.
845adc4f0dbSShawn McCarney  *
846adc4f0dbSShawn McCarney  * @param inventoryItem Inventory item where data will be stored.
847adc4f0dbSShawn McCarney  * @param interfacesDict Map containing D-Bus interfaces and their properties
848adc4f0dbSShawn McCarney  * for the specified inventory item.
849adc4f0dbSShawn McCarney  */
85023a21a1cSEd Tanous inline void storeInventoryItemData(
851adc4f0dbSShawn McCarney     InventoryItem& inventoryItem,
85280f79a40SMichael Shen     const dbus::utility::DBusInterfacesMap& interfacesDict)
8538fb49dd6SShawn McCarney {
854adc4f0dbSShawn McCarney     // Get properties from Inventory.Item interface
855711ac7a9SEd Tanous 
8569eb808c1SEd Tanous     for (const auto& [interface, values] : interfacesDict)
8578fb49dd6SShawn McCarney     {
858711ac7a9SEd Tanous         if (interface == "xyz.openbmc_project.Inventory.Item")
8598fb49dd6SShawn McCarney         {
8609eb808c1SEd Tanous             for (const auto& [name, dbusValue] : values)
861711ac7a9SEd Tanous             {
862711ac7a9SEd Tanous                 if (name == "Present")
863711ac7a9SEd Tanous                 {
864711ac7a9SEd Tanous                     const bool* value = std::get_if<bool>(&dbusValue);
865adc4f0dbSShawn McCarney                     if (value != nullptr)
8668fb49dd6SShawn McCarney                     {
867adc4f0dbSShawn McCarney                         inventoryItem.isPresent = *value;
8688fb49dd6SShawn McCarney                     }
8698fb49dd6SShawn McCarney                 }
8708fb49dd6SShawn McCarney             }
871711ac7a9SEd Tanous         }
872adc4f0dbSShawn McCarney         // Check if Inventory.Item.PowerSupply interface is present
873711ac7a9SEd Tanous 
874711ac7a9SEd Tanous         if (interface == "xyz.openbmc_project.Inventory.Item.PowerSupply")
8758fb49dd6SShawn McCarney         {
876adc4f0dbSShawn McCarney             inventoryItem.isPowerSupply = true;
8778fb49dd6SShawn McCarney         }
878adc4f0dbSShawn McCarney 
879adc4f0dbSShawn McCarney         // Get properties from Inventory.Decorator.Asset interface
880711ac7a9SEd Tanous         if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
881adc4f0dbSShawn McCarney         {
8829eb808c1SEd Tanous             for (const auto& [name, dbusValue] : values)
883711ac7a9SEd Tanous             {
884711ac7a9SEd Tanous                 if (name == "Manufacturer")
885adc4f0dbSShawn McCarney                 {
886adc4f0dbSShawn McCarney                     const std::string* value =
887711ac7a9SEd Tanous                         std::get_if<std::string>(&dbusValue);
888adc4f0dbSShawn McCarney                     if (value != nullptr)
889adc4f0dbSShawn McCarney                     {
890adc4f0dbSShawn McCarney                         inventoryItem.manufacturer = *value;
891adc4f0dbSShawn McCarney                     }
892adc4f0dbSShawn McCarney                 }
893711ac7a9SEd Tanous                 if (name == "Model")
894adc4f0dbSShawn McCarney                 {
895adc4f0dbSShawn McCarney                     const std::string* value =
896711ac7a9SEd Tanous                         std::get_if<std::string>(&dbusValue);
897adc4f0dbSShawn McCarney                     if (value != nullptr)
898adc4f0dbSShawn McCarney                     {
899adc4f0dbSShawn McCarney                         inventoryItem.model = *value;
900adc4f0dbSShawn McCarney                     }
901adc4f0dbSShawn McCarney                 }
902711ac7a9SEd Tanous                 if (name == "SerialNumber")
903adc4f0dbSShawn McCarney                 {
904adc4f0dbSShawn McCarney                     const std::string* value =
905711ac7a9SEd Tanous                         std::get_if<std::string>(&dbusValue);
906adc4f0dbSShawn McCarney                     if (value != nullptr)
907adc4f0dbSShawn McCarney                     {
908adc4f0dbSShawn McCarney                         inventoryItem.serialNumber = *value;
909adc4f0dbSShawn McCarney                     }
910adc4f0dbSShawn McCarney                 }
911711ac7a9SEd Tanous                 if (name == "PartNumber")
912711ac7a9SEd Tanous                 {
913711ac7a9SEd Tanous                     const std::string* value =
914711ac7a9SEd Tanous                         std::get_if<std::string>(&dbusValue);
915711ac7a9SEd Tanous                     if (value != nullptr)
916711ac7a9SEd Tanous                     {
917711ac7a9SEd Tanous                         inventoryItem.partNumber = *value;
918711ac7a9SEd Tanous                     }
919711ac7a9SEd Tanous                 }
920711ac7a9SEd Tanous             }
921adc4f0dbSShawn McCarney         }
922adc4f0dbSShawn McCarney 
923711ac7a9SEd Tanous         if (interface ==
924711ac7a9SEd Tanous             "xyz.openbmc_project.State.Decorator.OperationalStatus")
925adc4f0dbSShawn McCarney         {
9269eb808c1SEd Tanous             for (const auto& [name, dbusValue] : values)
927adc4f0dbSShawn McCarney             {
928711ac7a9SEd Tanous                 if (name == "Functional")
929711ac7a9SEd Tanous                 {
930711ac7a9SEd Tanous                     const bool* value = std::get_if<bool>(&dbusValue);
931adc4f0dbSShawn McCarney                     if (value != nullptr)
932adc4f0dbSShawn McCarney                     {
933adc4f0dbSShawn McCarney                         inventoryItem.isFunctional = *value;
9348fb49dd6SShawn McCarney                     }
9358fb49dd6SShawn McCarney                 }
9368fb49dd6SShawn McCarney             }
9378fb49dd6SShawn McCarney         }
938711ac7a9SEd Tanous     }
939711ac7a9SEd Tanous }
9408fb49dd6SShawn McCarney 
9418fb49dd6SShawn McCarney /**
942adc4f0dbSShawn McCarney  * @brief Gets D-Bus data for inventory items associated with sensors.
9438fb49dd6SShawn McCarney  *
944adc4f0dbSShawn McCarney  * Uses the specified connections (services) to obtain D-Bus data for inventory
945adc4f0dbSShawn McCarney  * items associated with sensors.  Stores the resulting data in the
946adc4f0dbSShawn McCarney  * inventoryItems vector.
9478fb49dd6SShawn McCarney  *
948adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
949adc4f0dbSShawn McCarney  * response.
950adc4f0dbSShawn McCarney  *
951adc4f0dbSShawn McCarney  * Finds the inventory item data asynchronously.  Invokes callback when data has
952adc4f0dbSShawn McCarney  * been obtained.
953adc4f0dbSShawn McCarney  *
954adc4f0dbSShawn McCarney  * The callback must have the following signature:
955adc4f0dbSShawn McCarney  *   @code
956d500549bSAnthony Wilson  *   callback(void)
957adc4f0dbSShawn McCarney  *   @endcode
958adc4f0dbSShawn McCarney  *
959adc4f0dbSShawn McCarney  * This function is called recursively, obtaining data asynchronously from one
960adc4f0dbSShawn McCarney  * connection in each call.  This ensures the callback is not invoked until the
961adc4f0dbSShawn McCarney  * last asynchronous function has completed.
9628fb49dd6SShawn McCarney  *
9638fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
964adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
965adc4f0dbSShawn McCarney  * @param invConnections Connections that provide data for the inventory items.
9668fb49dd6SShawn McCarney  * implements ObjectManager.
967adc4f0dbSShawn McCarney  * @param callback Callback to invoke when inventory data has been obtained.
968adc4f0dbSShawn McCarney  * @param invConnectionsIndex Current index in invConnections.  Only specified
969adc4f0dbSShawn McCarney  * in recursive calls to this function.
9708fb49dd6SShawn McCarney  */
971adc4f0dbSShawn McCarney template <typename Callback>
9724ff0f1f4SEd Tanous void getInventoryItemsData(
9738fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
974adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
975d0090733SEd Tanous     std::shared_ptr<std::set<std::string>> invConnections, Callback&& callback,
976d0090733SEd Tanous     size_t invConnectionsIndex = 0)
9778fb49dd6SShawn McCarney {
97862598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemsData enter");
9798fb49dd6SShawn McCarney 
980adc4f0dbSShawn McCarney     // If no more connections left, call callback
981adc4f0dbSShawn McCarney     if (invConnectionsIndex >= invConnections->size())
9828fb49dd6SShawn McCarney     {
983d500549bSAnthony Wilson         callback();
98462598e31SEd Tanous         BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
985adc4f0dbSShawn McCarney         return;
986adc4f0dbSShawn McCarney     }
987adc4f0dbSShawn McCarney 
988adc4f0dbSShawn McCarney     // Get inventory item data from current connection
989fe04d49cSNan Zhou     auto it = invConnections->begin();
990fe04d49cSNan Zhou     std::advance(it, invConnectionsIndex);
991adc4f0dbSShawn McCarney     if (it != invConnections->end())
992adc4f0dbSShawn McCarney     {
993adc4f0dbSShawn McCarney         const std::string& invConnection = *it;
994adc4f0dbSShawn McCarney 
9955eb468daSGeorge Liu         // Get all object paths and their interfaces for current connection
9965eb468daSGeorge Liu         sdbusplus::message::object_path path("/xyz/openbmc_project/inventory");
9975eb468daSGeorge Liu         dbus::utility::getManagedObjects(
9985eb468daSGeorge Liu             invConnection, path,
9995eb468daSGeorge Liu             [sensorsAsyncResp, inventoryItems, invConnections,
10008cb2c024SEd Tanous              callback = std::forward<Callback>(callback), invConnectionsIndex](
10015e7e2dc5SEd Tanous                 const boost::system::error_code& ec,
10024e0d8789SEd Tanous                 const dbus::utility::ManagedObjectType& resp) mutable {
100362598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler enter");
10048fb49dd6SShawn McCarney                 if (ec)
10058fb49dd6SShawn McCarney                 {
100662598e31SEd Tanous                     BMCWEB_LOG_ERROR(
100762598e31SEd Tanous                         "getInventoryItemsData respHandler DBus error {}", ec);
10088d1b46d7Szhanghch05                     messages::internalError(sensorsAsyncResp->asyncResp->res);
10098fb49dd6SShawn McCarney                     return;
10108fb49dd6SShawn McCarney                 }
10118fb49dd6SShawn McCarney 
10128fb49dd6SShawn McCarney                 // Loop through returned object paths
10138fb49dd6SShawn McCarney                 for (const auto& objDictEntry : resp)
10148fb49dd6SShawn McCarney                 {
10158fb49dd6SShawn McCarney                     const std::string& objPath =
10168fb49dd6SShawn McCarney                         static_cast<const std::string&>(objDictEntry.first);
10178fb49dd6SShawn McCarney 
1018bd79bce8SPatrick Williams                     // If this object path is one of the specified inventory
1019bd79bce8SPatrick Williams                     // items
1020bd79bce8SPatrick Williams                     InventoryItem* inventoryItem =
1021bd79bce8SPatrick Williams                         findInventoryItem(inventoryItems, objPath);
1022adc4f0dbSShawn McCarney                     if (inventoryItem != nullptr)
10238fb49dd6SShawn McCarney                     {
1024adc4f0dbSShawn McCarney                         // Store inventory data in InventoryItem
1025bd79bce8SPatrick Williams                         storeInventoryItemData(*inventoryItem,
1026bd79bce8SPatrick Williams                                                objDictEntry.second);
10278fb49dd6SShawn McCarney                     }
10288fb49dd6SShawn McCarney                 }
10298fb49dd6SShawn McCarney 
1030adc4f0dbSShawn McCarney                 // Recurse to get inventory item data from next connection
1031adc4f0dbSShawn McCarney                 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1032d0090733SEd Tanous                                       invConnections, std::move(callback),
1033d0090733SEd Tanous                                       invConnectionsIndex + 1);
1034adc4f0dbSShawn McCarney 
103562598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler exit");
10365eb468daSGeorge Liu             });
10378fb49dd6SShawn McCarney     }
10388fb49dd6SShawn McCarney 
103962598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
10408fb49dd6SShawn McCarney }
10418fb49dd6SShawn McCarney 
10428fb49dd6SShawn McCarney /**
1043adc4f0dbSShawn McCarney  * @brief Gets connections that provide D-Bus data for inventory items.
10448fb49dd6SShawn McCarney  *
1045adc4f0dbSShawn McCarney  * Gets the D-Bus connections (services) that provide data for the inventory
1046adc4f0dbSShawn McCarney  * items that are associated with sensors.
10478fb49dd6SShawn McCarney  *
10488fb49dd6SShawn McCarney  * Finds the connections asynchronously.  Invokes callback when information has
10498fb49dd6SShawn McCarney  * been obtained.
10508fb49dd6SShawn McCarney  *
10518fb49dd6SShawn McCarney  * The callback must have the following signature:
10528fb49dd6SShawn McCarney  *   @code
1053fe04d49cSNan Zhou  *   callback(std::shared_ptr<std::set<std::string>> invConnections)
10548fb49dd6SShawn McCarney  *   @endcode
10558fb49dd6SShawn McCarney  *
10568fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
1057adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
10588fb49dd6SShawn McCarney  * @param callback Callback to invoke when connections have been obtained.
10598fb49dd6SShawn McCarney  */
10608fb49dd6SShawn McCarney template <typename Callback>
10614ff0f1f4SEd Tanous void getInventoryItemsConnections(
1062b5a76932SEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1063b5a76932SEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
10648fb49dd6SShawn McCarney     Callback&& callback)
10658fb49dd6SShawn McCarney {
106662598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemsConnections enter");
10678fb49dd6SShawn McCarney 
10688fb49dd6SShawn McCarney     const std::string path = "/xyz/openbmc_project/inventory";
1069e99073f5SGeorge Liu     constexpr std::array<std::string_view, 4> interfaces = {
10708fb49dd6SShawn McCarney         "xyz.openbmc_project.Inventory.Item",
1071adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Item.PowerSupply",
1072adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Decorator.Asset",
10738fb49dd6SShawn McCarney         "xyz.openbmc_project.State.Decorator.OperationalStatus"};
10748fb49dd6SShawn McCarney 
1075e99073f5SGeorge Liu     // Make call to ObjectMapper to find all inventory items
1076e99073f5SGeorge Liu     dbus::utility::getSubTree(
1077e99073f5SGeorge Liu         path, 0, interfaces,
10788cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), sensorsAsyncResp,
1079002d39b4SEd Tanous          inventoryItems](
1080e99073f5SGeorge Liu             const boost::system::error_code& ec,
10814e0d8789SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
1082e99073f5SGeorge Liu             // Response handler for parsing output from GetSubTree
108362598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler enter");
10848fb49dd6SShawn McCarney             if (ec)
10858fb49dd6SShawn McCarney             {
10868d1b46d7Szhanghch05                 messages::internalError(sensorsAsyncResp->asyncResp->res);
108762598e31SEd Tanous                 BMCWEB_LOG_ERROR(
1088bd79bce8SPatrick Williams                     "getInventoryItemsConnections respHandler DBus error {}",
1089bd79bce8SPatrick Williams                     ec);
10908fb49dd6SShawn McCarney                 return;
10918fb49dd6SShawn McCarney             }
10928fb49dd6SShawn McCarney 
10938fb49dd6SShawn McCarney             // Make unique list of connections for desired inventory items
1094fe04d49cSNan Zhou             std::shared_ptr<std::set<std::string>> invConnections =
1095fe04d49cSNan Zhou                 std::make_shared<std::set<std::string>>();
10968fb49dd6SShawn McCarney 
10978fb49dd6SShawn McCarney             // Loop through objects from GetSubTree
1098bd79bce8SPatrick Williams             for (const std::pair<std::string,
1099bd79bce8SPatrick Williams                                  std::vector<std::pair<
1100bd79bce8SPatrick Williams                                      std::string, std::vector<std::string>>>>&
11018fb49dd6SShawn McCarney                      object : subtree)
11028fb49dd6SShawn McCarney             {
1103adc4f0dbSShawn McCarney                 // Check if object path is one of the specified inventory items
11048fb49dd6SShawn McCarney                 const std::string& objPath = object.first;
1105adc4f0dbSShawn McCarney                 if (findInventoryItem(inventoryItems, objPath) != nullptr)
11068fb49dd6SShawn McCarney                 {
11078fb49dd6SShawn McCarney                     // Store all connections to inventory item
11088fb49dd6SShawn McCarney                     for (const std::pair<std::string, std::vector<std::string>>&
11098fb49dd6SShawn McCarney                              objData : object.second)
11108fb49dd6SShawn McCarney                     {
11118fb49dd6SShawn McCarney                         const std::string& invConnection = objData.first;
11128fb49dd6SShawn McCarney                         invConnections->insert(invConnection);
11138fb49dd6SShawn McCarney                     }
11148fb49dd6SShawn McCarney                 }
11158fb49dd6SShawn McCarney             }
1116d500549bSAnthony Wilson 
11178fb49dd6SShawn McCarney             callback(invConnections);
111862598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler exit");
1119e99073f5SGeorge Liu         });
112062598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemsConnections exit");
11218fb49dd6SShawn McCarney }
11228fb49dd6SShawn McCarney 
11238fb49dd6SShawn McCarney /**
1124adc4f0dbSShawn McCarney  * @brief Gets associations from sensors to inventory items.
11258fb49dd6SShawn McCarney  *
11268fb49dd6SShawn McCarney  * Looks for ObjectMapper associations from the specified sensors to related
1127d500549bSAnthony Wilson  * inventory items. Then finds the associations from those inventory items to
1128d500549bSAnthony Wilson  * their LEDs, if any.
11298fb49dd6SShawn McCarney  *
11308fb49dd6SShawn McCarney  * Finds the inventory items asynchronously.  Invokes callback when information
11318fb49dd6SShawn McCarney  * has been obtained.
11328fb49dd6SShawn McCarney  *
11338fb49dd6SShawn McCarney  * The callback must have the following signature:
11348fb49dd6SShawn McCarney  *   @code
1135adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
11368fb49dd6SShawn McCarney  *   @endcode
11378fb49dd6SShawn McCarney  *
11388fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
11398fb49dd6SShawn McCarney  * @param sensorNames All sensors within the current chassis.
11408fb49dd6SShawn McCarney  * implements ObjectManager.
11418fb49dd6SShawn McCarney  * @param callback Callback to invoke when inventory items have been obtained.
11428fb49dd6SShawn McCarney  */
11438fb49dd6SShawn McCarney template <typename Callback>
11444ff0f1f4SEd Tanous void getInventoryItemAssociations(
1145b5a76932SEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1146fe04d49cSNan Zhou     const std::shared_ptr<std::set<std::string>>& sensorNames,
11478fb49dd6SShawn McCarney     Callback&& callback)
11488fb49dd6SShawn McCarney {
114962598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemAssociations enter");
11508fb49dd6SShawn McCarney 
11515eb468daSGeorge Liu     // Call GetManagedObjects on the ObjectMapper to get all associations
11525eb468daSGeorge Liu     sdbusplus::message::object_path path("/");
11535eb468daSGeorge Liu     dbus::utility::getManagedObjects(
11545eb468daSGeorge Liu         "xyz.openbmc_project.ObjectMapper", path,
11558cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), sensorsAsyncResp,
11565e7e2dc5SEd Tanous          sensorNames](const boost::system::error_code& ec,
11574e0d8789SEd Tanous                       const dbus::utility::ManagedObjectType& resp) mutable {
115862598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler enter");
11598fb49dd6SShawn McCarney             if (ec)
11608fb49dd6SShawn McCarney             {
116162598e31SEd Tanous                 BMCWEB_LOG_ERROR(
1162bd79bce8SPatrick Williams                     "getInventoryItemAssociations respHandler DBus error {}",
1163bd79bce8SPatrick Williams                     ec);
11648d1b46d7Szhanghch05                 messages::internalError(sensorsAsyncResp->asyncResp->res);
11658fb49dd6SShawn McCarney                 return;
11668fb49dd6SShawn McCarney             }
11678fb49dd6SShawn McCarney 
1168adc4f0dbSShawn McCarney             // Create vector to hold list of inventory items
1169adc4f0dbSShawn McCarney             std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1170adc4f0dbSShawn McCarney                 std::make_shared<std::vector<InventoryItem>>();
1171adc4f0dbSShawn McCarney 
11728fb49dd6SShawn McCarney             // Loop through returned object paths
11738fb49dd6SShawn McCarney             std::string sensorAssocPath;
11748fb49dd6SShawn McCarney             sensorAssocPath.reserve(128); // avoid memory allocations
11758fb49dd6SShawn McCarney             for (const auto& objDictEntry : resp)
11768fb49dd6SShawn McCarney             {
11778fb49dd6SShawn McCarney                 const std::string& objPath =
11788fb49dd6SShawn McCarney                     static_cast<const std::string&>(objDictEntry.first);
11798fb49dd6SShawn McCarney 
1180bd79bce8SPatrick Williams                 // If path is inventory association for one of the specified
1181bd79bce8SPatrick Williams                 // sensors
11828fb49dd6SShawn McCarney                 for (const std::string& sensorName : *sensorNames)
11838fb49dd6SShawn McCarney                 {
11848fb49dd6SShawn McCarney                     sensorAssocPath = sensorName;
11858fb49dd6SShawn McCarney                     sensorAssocPath += "/inventory";
11868fb49dd6SShawn McCarney                     if (objPath == sensorAssocPath)
11878fb49dd6SShawn McCarney                     {
11888fb49dd6SShawn McCarney                         // Get Association interface for object path
1189bd79bce8SPatrick Williams                         for (const auto& [interface, values] :
1190bd79bce8SPatrick Williams                              objDictEntry.second)
11918fb49dd6SShawn McCarney                         {
1192711ac7a9SEd Tanous                             if (interface == "xyz.openbmc_project.Association")
1193711ac7a9SEd Tanous                             {
1194711ac7a9SEd Tanous                                 for (const auto& [valueName, value] : values)
1195711ac7a9SEd Tanous                                 {
1196711ac7a9SEd Tanous                                     if (valueName == "endpoints")
11978fb49dd6SShawn McCarney                                     {
1198bd79bce8SPatrick Williams                                         const std::vector<std::string>*
1199bd79bce8SPatrick Williams                                             endpoints = std::get_if<
1200bd79bce8SPatrick Williams                                                 std::vector<std::string>>(
1201711ac7a9SEd Tanous                                                 &value);
1202711ac7a9SEd Tanous                                         if ((endpoints != nullptr) &&
1203711ac7a9SEd Tanous                                             !endpoints->empty())
12048fb49dd6SShawn McCarney                                         {
1205adc4f0dbSShawn McCarney                                             // Add inventory item to vector
1206adc4f0dbSShawn McCarney                                             const std::string& invItemPath =
1207adc4f0dbSShawn McCarney                                                 endpoints->front();
1208711ac7a9SEd Tanous                                             addInventoryItem(inventoryItems,
1209711ac7a9SEd Tanous                                                              invItemPath,
1210adc4f0dbSShawn McCarney                                                              sensorName);
12118fb49dd6SShawn McCarney                                         }
12128fb49dd6SShawn McCarney                                     }
12138fb49dd6SShawn McCarney                                 }
1214711ac7a9SEd Tanous                             }
1215711ac7a9SEd Tanous                         }
12168fb49dd6SShawn McCarney                         break;
12178fb49dd6SShawn McCarney                     }
12188fb49dd6SShawn McCarney                 }
12198fb49dd6SShawn McCarney             }
12208fb49dd6SShawn McCarney 
1221d500549bSAnthony Wilson             // Now loop through the returned object paths again, this time to
1222d500549bSAnthony Wilson             // find the leds associated with the inventory items we just found
1223d500549bSAnthony Wilson             std::string inventoryAssocPath;
1224d500549bSAnthony Wilson             inventoryAssocPath.reserve(128); // avoid memory allocations
1225d500549bSAnthony Wilson             for (const auto& objDictEntry : resp)
1226d500549bSAnthony Wilson             {
1227d500549bSAnthony Wilson                 const std::string& objPath =
1228d500549bSAnthony Wilson                     static_cast<const std::string&>(objDictEntry.first);
1229d500549bSAnthony Wilson 
1230d500549bSAnthony Wilson                 for (InventoryItem& inventoryItem : *inventoryItems)
1231d500549bSAnthony Wilson                 {
1232d500549bSAnthony Wilson                     inventoryAssocPath = inventoryItem.objectPath;
1233d500549bSAnthony Wilson                     inventoryAssocPath += "/leds";
1234d500549bSAnthony Wilson                     if (objPath == inventoryAssocPath)
1235d500549bSAnthony Wilson                     {
1236bd79bce8SPatrick Williams                         for (const auto& [interface, values] :
1237bd79bce8SPatrick Williams                              objDictEntry.second)
1238d500549bSAnthony Wilson                         {
1239711ac7a9SEd Tanous                             if (interface == "xyz.openbmc_project.Association")
1240711ac7a9SEd Tanous                             {
1241711ac7a9SEd Tanous                                 for (const auto& [valueName, value] : values)
1242711ac7a9SEd Tanous                                 {
1243711ac7a9SEd Tanous                                     if (valueName == "endpoints")
1244d500549bSAnthony Wilson                                     {
1245bd79bce8SPatrick Williams                                         const std::vector<std::string>*
1246bd79bce8SPatrick Williams                                             endpoints = std::get_if<
1247bd79bce8SPatrick Williams                                                 std::vector<std::string>>(
1248711ac7a9SEd Tanous                                                 &value);
1249711ac7a9SEd Tanous                                         if ((endpoints != nullptr) &&
1250711ac7a9SEd Tanous                                             !endpoints->empty())
1251d500549bSAnthony Wilson                                         {
1252711ac7a9SEd Tanous                                             // Add inventory item to vector
1253d500549bSAnthony Wilson                                             // Store LED path in inventory item
1254711ac7a9SEd Tanous                                             const std::string& ledPath =
1255711ac7a9SEd Tanous                                                 endpoints->front();
1256bd79bce8SPatrick Williams                                             inventoryItem.ledObjectPath =
1257bd79bce8SPatrick Williams                                                 ledPath;
1258d500549bSAnthony Wilson                                         }
1259d500549bSAnthony Wilson                                     }
1260d500549bSAnthony Wilson                                 }
1261711ac7a9SEd Tanous                             }
1262711ac7a9SEd Tanous                         }
1263711ac7a9SEd Tanous 
1264d500549bSAnthony Wilson                         break;
1265d500549bSAnthony Wilson                     }
1266d500549bSAnthony Wilson                 }
1267d500549bSAnthony Wilson             }
1268adc4f0dbSShawn McCarney             callback(inventoryItems);
126962598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler exit");
12705eb468daSGeorge Liu         });
12718fb49dd6SShawn McCarney 
127262598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItemAssociations exit");
12738fb49dd6SShawn McCarney }
12748fb49dd6SShawn McCarney 
12758fb49dd6SShawn McCarney /**
1276d500549bSAnthony Wilson  * @brief Gets D-Bus data for inventory item leds associated with sensors.
1277d500549bSAnthony Wilson  *
1278d500549bSAnthony Wilson  * Uses the specified connections (services) to obtain D-Bus data for inventory
1279d500549bSAnthony Wilson  * item leds associated with sensors.  Stores the resulting data in the
1280d500549bSAnthony Wilson  * inventoryItems vector.
1281d500549bSAnthony Wilson  *
1282d500549bSAnthony Wilson  * This data is later used to provide sensor property values in the JSON
1283d500549bSAnthony Wilson  * response.
1284d500549bSAnthony Wilson  *
1285d500549bSAnthony Wilson  * Finds the inventory item led data asynchronously.  Invokes callback when data
1286d500549bSAnthony Wilson  * has been obtained.
1287d500549bSAnthony Wilson  *
1288d500549bSAnthony Wilson  * The callback must have the following signature:
1289d500549bSAnthony Wilson  *   @code
129042cbe538SGunnar Mills  *   callback()
1291d500549bSAnthony Wilson  *   @endcode
1292d500549bSAnthony Wilson  *
1293d500549bSAnthony Wilson  * This function is called recursively, obtaining data asynchronously from one
1294d500549bSAnthony Wilson  * connection in each call.  This ensures the callback is not invoked until the
1295d500549bSAnthony Wilson  * last asynchronous function has completed.
1296d500549bSAnthony Wilson  *
1297d500549bSAnthony Wilson  * @param sensorsAsyncResp Pointer to object holding response data.
1298d500549bSAnthony Wilson  * @param inventoryItems D-Bus inventory items associated with sensors.
1299d500549bSAnthony Wilson  * @param ledConnections Connections that provide data for the inventory leds.
1300d500549bSAnthony Wilson  * @param callback Callback to invoke when inventory data has been obtained.
1301d500549bSAnthony Wilson  * @param ledConnectionsIndex Current index in ledConnections.  Only specified
1302d500549bSAnthony Wilson  * in recursive calls to this function.
1303d500549bSAnthony Wilson  */
1304d500549bSAnthony Wilson template <typename Callback>
1305d500549bSAnthony Wilson void getInventoryLedData(
1306d500549bSAnthony Wilson     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1307d500549bSAnthony Wilson     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1308fe04d49cSNan Zhou     std::shared_ptr<std::map<std::string, std::string>> ledConnections,
1309d500549bSAnthony Wilson     Callback&& callback, size_t ledConnectionsIndex = 0)
1310d500549bSAnthony Wilson {
131162598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryLedData enter");
1312d500549bSAnthony Wilson 
1313d500549bSAnthony Wilson     // If no more connections left, call callback
1314d500549bSAnthony Wilson     if (ledConnectionsIndex >= ledConnections->size())
1315d500549bSAnthony Wilson     {
131642cbe538SGunnar Mills         callback();
131762598e31SEd Tanous         BMCWEB_LOG_DEBUG("getInventoryLedData exit");
1318d500549bSAnthony Wilson         return;
1319d500549bSAnthony Wilson     }
1320d500549bSAnthony Wilson 
1321d500549bSAnthony Wilson     // Get inventory item data from current connection
1322fe04d49cSNan Zhou     auto it = ledConnections->begin();
1323fe04d49cSNan Zhou     std::advance(it, ledConnectionsIndex);
1324d500549bSAnthony Wilson     if (it != ledConnections->end())
1325d500549bSAnthony Wilson     {
1326d500549bSAnthony Wilson         const std::string& ledPath = (*it).first;
1327d500549bSAnthony Wilson         const std::string& ledConnection = (*it).second;
1328d500549bSAnthony Wilson         // Response handler for Get State property
13291e1e598dSJonathan Doman         auto respHandler =
13301e1e598dSJonathan Doman             [sensorsAsyncResp, inventoryItems, ledConnections, ledPath,
13314e0d8789SEd Tanous              callback = std::forward<Callback>(callback),
13324e0d8789SEd Tanous              ledConnectionsIndex](const boost::system::error_code& ec,
13334e0d8789SEd Tanous                                   const std::string& state) mutable {
133462598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler enter");
1335d500549bSAnthony Wilson                 if (ec)
1336d500549bSAnthony Wilson                 {
133762598e31SEd Tanous                     BMCWEB_LOG_ERROR(
133862598e31SEd Tanous                         "getInventoryLedData respHandler DBus error {}", ec);
13398d1b46d7Szhanghch05                     messages::internalError(sensorsAsyncResp->asyncResp->res);
1340d500549bSAnthony Wilson                     return;
1341d500549bSAnthony Wilson                 }
1342d500549bSAnthony Wilson 
134362598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Led state: {}", state);
1344d500549bSAnthony Wilson                 // Find inventory item with this LED object path
1345d500549bSAnthony Wilson                 InventoryItem* inventoryItem =
1346d500549bSAnthony Wilson                     findInventoryItemForLed(*inventoryItems, ledPath);
1347d500549bSAnthony Wilson                 if (inventoryItem != nullptr)
1348d500549bSAnthony Wilson                 {
1349d500549bSAnthony Wilson                     // Store LED state in InventoryItem
135011ba3979SEd Tanous                     if (state.ends_with("On"))
1351d500549bSAnthony Wilson                     {
1352c9563608SJanet Adkins                         inventoryItem->ledState = sensor_utils::LedState::ON;
1353d500549bSAnthony Wilson                     }
135411ba3979SEd Tanous                     else if (state.ends_with("Blink"))
1355d500549bSAnthony Wilson                     {
1356c9563608SJanet Adkins                         inventoryItem->ledState = sensor_utils::LedState::BLINK;
1357d500549bSAnthony Wilson                     }
135811ba3979SEd Tanous                     else if (state.ends_with("Off"))
1359d500549bSAnthony Wilson                     {
1360c9563608SJanet Adkins                         inventoryItem->ledState = sensor_utils::LedState::OFF;
1361d500549bSAnthony Wilson                     }
1362d500549bSAnthony Wilson                     else
1363d500549bSAnthony Wilson                     {
1364c9563608SJanet Adkins                         inventoryItem->ledState =
1365c9563608SJanet Adkins                             sensor_utils::LedState::UNKNOWN;
1366d500549bSAnthony Wilson                     }
1367d500549bSAnthony Wilson                 }
1368d500549bSAnthony Wilson 
1369d500549bSAnthony Wilson                 // Recurse to get LED data from next connection
1370d500549bSAnthony Wilson                 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1371d500549bSAnthony Wilson                                     ledConnections, std::move(callback),
1372d500549bSAnthony Wilson                                     ledConnectionsIndex + 1);
1373d500549bSAnthony Wilson 
137462598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler exit");
1375d500549bSAnthony Wilson             };
1376d500549bSAnthony Wilson 
1377d500549bSAnthony Wilson         // Get the State property for the current LED
1378*deae6a78SEd Tanous         dbus::utility::getProperty<std::string>(
1379*deae6a78SEd Tanous             ledConnection, ledPath, "xyz.openbmc_project.Led.Physical", "State",
13801e1e598dSJonathan Doman             std::move(respHandler));
1381d500549bSAnthony Wilson     }
1382d500549bSAnthony Wilson 
138362598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryLedData exit");
1384d500549bSAnthony Wilson }
1385d500549bSAnthony Wilson 
1386d500549bSAnthony Wilson /**
1387d500549bSAnthony Wilson  * @brief Gets LED data for LEDs associated with given inventory items.
1388d500549bSAnthony Wilson  *
1389d500549bSAnthony Wilson  * Gets the D-Bus connections (services) that provide LED data for the LEDs
1390d500549bSAnthony Wilson  * associated with the specified inventory items.  Then gets the LED data from
1391d500549bSAnthony Wilson  * each connection and stores it in the inventory item.
1392d500549bSAnthony Wilson  *
1393d500549bSAnthony Wilson  * This data is later used to provide sensor property values in the JSON
1394d500549bSAnthony Wilson  * response.
1395d500549bSAnthony Wilson  *
1396d500549bSAnthony Wilson  * Finds the LED data asynchronously.  Invokes callback when information has
1397d500549bSAnthony Wilson  * been obtained.
1398d500549bSAnthony Wilson  *
1399d500549bSAnthony Wilson  * The callback must have the following signature:
1400d500549bSAnthony Wilson  *   @code
140142cbe538SGunnar Mills  *   callback()
1402d500549bSAnthony Wilson  *   @endcode
1403d500549bSAnthony Wilson  *
1404d500549bSAnthony Wilson  * @param sensorsAsyncResp Pointer to object holding response data.
1405d500549bSAnthony Wilson  * @param inventoryItems D-Bus inventory items associated with sensors.
1406d500549bSAnthony Wilson  * @param callback Callback to invoke when inventory items have been obtained.
1407d500549bSAnthony Wilson  */
1408d500549bSAnthony Wilson template <typename Callback>
1409d500549bSAnthony Wilson void getInventoryLeds(
1410d500549bSAnthony Wilson     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1411d500549bSAnthony Wilson     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1412d500549bSAnthony Wilson     Callback&& callback)
1413d500549bSAnthony Wilson {
141462598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryLeds enter");
1415d500549bSAnthony Wilson 
1416d500549bSAnthony Wilson     const std::string path = "/xyz/openbmc_project";
1417e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
1418d500549bSAnthony Wilson         "xyz.openbmc_project.Led.Physical"};
1419d500549bSAnthony Wilson 
1420e99073f5SGeorge Liu     // Make call to ObjectMapper to find all inventory items
1421e99073f5SGeorge Liu     dbus::utility::getSubTree(
1422e99073f5SGeorge Liu         path, 0, interfaces,
14238cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), sensorsAsyncResp,
1424002d39b4SEd Tanous          inventoryItems](
1425e99073f5SGeorge Liu             const boost::system::error_code& ec,
14264e0d8789SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
1427e99073f5SGeorge Liu             // Response handler for parsing output from GetSubTree
142862598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryLeds respHandler enter");
1429d500549bSAnthony Wilson             if (ec)
1430d500549bSAnthony Wilson             {
14318d1b46d7Szhanghch05                 messages::internalError(sensorsAsyncResp->asyncResp->res);
1432bd79bce8SPatrick Williams                 BMCWEB_LOG_ERROR("getInventoryLeds respHandler DBus error {}",
1433bd79bce8SPatrick Williams                                  ec);
1434d500549bSAnthony Wilson                 return;
1435d500549bSAnthony Wilson             }
1436d500549bSAnthony Wilson 
1437d500549bSAnthony Wilson             // Build map of LED object paths to connections
1438fe04d49cSNan Zhou             std::shared_ptr<std::map<std::string, std::string>> ledConnections =
1439fe04d49cSNan Zhou                 std::make_shared<std::map<std::string, std::string>>();
1440d500549bSAnthony Wilson 
1441d500549bSAnthony Wilson             // Loop through objects from GetSubTree
1442bd79bce8SPatrick Williams             for (const std::pair<std::string,
1443bd79bce8SPatrick Williams                                  std::vector<std::pair<
1444bd79bce8SPatrick Williams                                      std::string, std::vector<std::string>>>>&
1445d500549bSAnthony Wilson                      object : subtree)
1446d500549bSAnthony Wilson             {
1447bd79bce8SPatrick Williams                 // Check if object path is LED for one of the specified
1448bd79bce8SPatrick Williams                 // inventory items
1449d500549bSAnthony Wilson                 const std::string& ledPath = object.first;
1450bd79bce8SPatrick Williams                 if (findInventoryItemForLed(*inventoryItems, ledPath) !=
1451bd79bce8SPatrick Williams                     nullptr)
1452d500549bSAnthony Wilson                 {
1453d500549bSAnthony Wilson                     // Add mapping from ledPath to connection
1454bd79bce8SPatrick Williams                     const std::string& connection =
1455bd79bce8SPatrick Williams                         object.second.begin()->first;
1456d500549bSAnthony Wilson                     (*ledConnections)[ledPath] = connection;
1457bd79bce8SPatrick Williams                     BMCWEB_LOG_DEBUG("Added mapping {} -> {}", ledPath,
1458bd79bce8SPatrick Williams                                      connection);
1459d500549bSAnthony Wilson                 }
1460d500549bSAnthony Wilson             }
1461d500549bSAnthony Wilson 
1462bd79bce8SPatrick Williams             getInventoryLedData(sensorsAsyncResp, inventoryItems,
1463bd79bce8SPatrick Williams                                 ledConnections, std::move(callback));
146462598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryLeds respHandler exit");
1465e99073f5SGeorge Liu         });
146662598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryLeds exit");
1467d500549bSAnthony Wilson }
1468d500549bSAnthony Wilson 
1469d500549bSAnthony Wilson /**
147042cbe538SGunnar Mills  * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent
147142cbe538SGunnar Mills  *
147242cbe538SGunnar Mills  * Uses the specified connections (services) (currently assumes just one) to
147342cbe538SGunnar Mills  * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in
147442cbe538SGunnar Mills  * the inventoryItems vector. Only stores data in Power Supply inventoryItems.
147542cbe538SGunnar Mills  *
147642cbe538SGunnar Mills  * This data is later used to provide sensor property values in the JSON
147742cbe538SGunnar Mills  * response.
147842cbe538SGunnar Mills  *
147942cbe538SGunnar Mills  * Finds the Power Supply Attributes data asynchronously.  Invokes callback
148042cbe538SGunnar Mills  * when data has been obtained.
148142cbe538SGunnar Mills  *
148242cbe538SGunnar Mills  * The callback must have the following signature:
148342cbe538SGunnar Mills  *   @code
148442cbe538SGunnar Mills  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
148542cbe538SGunnar Mills  *   @endcode
148642cbe538SGunnar Mills  *
148742cbe538SGunnar Mills  * @param sensorsAsyncResp Pointer to object holding response data.
148842cbe538SGunnar Mills  * @param inventoryItems D-Bus inventory items associated with sensors.
148942cbe538SGunnar Mills  * @param psAttributesConnections Connections that provide data for the Power
149042cbe538SGunnar Mills  *        Supply Attributes
149142cbe538SGunnar Mills  * @param callback Callback to invoke when data has been obtained.
149242cbe538SGunnar Mills  */
149342cbe538SGunnar Mills template <typename Callback>
149442cbe538SGunnar Mills void getPowerSupplyAttributesData(
1495b5a76932SEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
149642cbe538SGunnar Mills     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1497fe04d49cSNan Zhou     const std::map<std::string, std::string>& psAttributesConnections,
149842cbe538SGunnar Mills     Callback&& callback)
149942cbe538SGunnar Mills {
150062598e31SEd Tanous     BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData enter");
150142cbe538SGunnar Mills 
150242cbe538SGunnar Mills     if (psAttributesConnections.empty())
150342cbe538SGunnar Mills     {
150462598e31SEd Tanous         BMCWEB_LOG_DEBUG("Can't find PowerSupplyAttributes, no connections!");
150542cbe538SGunnar Mills         callback(inventoryItems);
150642cbe538SGunnar Mills         return;
150742cbe538SGunnar Mills     }
150842cbe538SGunnar Mills 
150942cbe538SGunnar Mills     // Assuming just one connection (service) for now
1510fe04d49cSNan Zhou     auto it = psAttributesConnections.begin();
151142cbe538SGunnar Mills 
151242cbe538SGunnar Mills     const std::string& psAttributesPath = (*it).first;
151342cbe538SGunnar Mills     const std::string& psAttributesConnection = (*it).second;
151442cbe538SGunnar Mills 
151542cbe538SGunnar Mills     // Response handler for Get DeratingFactor property
15165a39f77aSPatrick Williams     auto respHandler = [sensorsAsyncResp, inventoryItems,
15178cb2c024SEd Tanous                         callback = std::forward<Callback>(callback)](
15185a39f77aSPatrick Williams                            const boost::system::error_code& ec,
15194e0d8789SEd Tanous                            uint32_t value) mutable {
152062598e31SEd Tanous         BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler enter");
152142cbe538SGunnar Mills         if (ec)
152242cbe538SGunnar Mills         {
152362598e31SEd Tanous             BMCWEB_LOG_ERROR(
152462598e31SEd Tanous                 "getPowerSupplyAttributesData respHandler DBus error {}", ec);
15258d1b46d7Szhanghch05             messages::internalError(sensorsAsyncResp->asyncResp->res);
152642cbe538SGunnar Mills             return;
152742cbe538SGunnar Mills         }
152842cbe538SGunnar Mills 
152962598e31SEd Tanous         BMCWEB_LOG_DEBUG("PS EfficiencyPercent value: {}", value);
153042cbe538SGunnar Mills         // Store value in Power Supply Inventory Items
153142cbe538SGunnar Mills         for (InventoryItem& inventoryItem : *inventoryItems)
153242cbe538SGunnar Mills         {
153355f79e6fSEd Tanous             if (inventoryItem.isPowerSupply)
153442cbe538SGunnar Mills             {
153542cbe538SGunnar Mills                 inventoryItem.powerSupplyEfficiencyPercent =
15361e1e598dSJonathan Doman                     static_cast<int>(value);
153742cbe538SGunnar Mills             }
153842cbe538SGunnar Mills         }
153942cbe538SGunnar Mills 
154062598e31SEd Tanous         BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler exit");
154142cbe538SGunnar Mills         callback(inventoryItems);
154242cbe538SGunnar Mills     };
154342cbe538SGunnar Mills 
154442cbe538SGunnar Mills     // Get the DeratingFactor property for the PowerSupplyAttributes
154542cbe538SGunnar Mills     // Currently only property on the interface/only one we care about
1546*deae6a78SEd Tanous     dbus::utility::getProperty<uint32_t>(
1547*deae6a78SEd Tanous         psAttributesConnection, psAttributesPath,
15481e1e598dSJonathan Doman         "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
15491e1e598dSJonathan Doman         std::move(respHandler));
155042cbe538SGunnar Mills 
155162598e31SEd Tanous     BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData exit");
155242cbe538SGunnar Mills }
155342cbe538SGunnar Mills 
155442cbe538SGunnar Mills /**
155542cbe538SGunnar Mills  * @brief Gets the Power Supply Attributes such as EfficiencyPercent
155642cbe538SGunnar Mills  *
155742cbe538SGunnar Mills  * Gets the D-Bus connection (service) that provides Power Supply Attributes
155842cbe538SGunnar Mills  * data. Then gets the Power Supply Attributes data from the connection
155942cbe538SGunnar Mills  * (currently just assumes 1 connection) and stores the data in the inventory
156042cbe538SGunnar Mills  * item.
156142cbe538SGunnar Mills  *
156242cbe538SGunnar Mills  * This data is later used to provide sensor property values in the JSON
156342cbe538SGunnar Mills  * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish.
156442cbe538SGunnar Mills  *
156542cbe538SGunnar Mills  * Finds the Power Supply Attributes data asynchronously. Invokes callback
156642cbe538SGunnar Mills  * when information has been obtained.
156742cbe538SGunnar Mills  *
156842cbe538SGunnar Mills  * The callback must have the following signature:
156942cbe538SGunnar Mills  *   @code
157042cbe538SGunnar Mills  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
157142cbe538SGunnar Mills  *   @endcode
157242cbe538SGunnar Mills  *
157342cbe538SGunnar Mills  * @param sensorsAsyncResp Pointer to object holding response data.
157442cbe538SGunnar Mills  * @param inventoryItems D-Bus inventory items associated with sensors.
157542cbe538SGunnar Mills  * @param callback Callback to invoke when data has been obtained.
157642cbe538SGunnar Mills  */
157742cbe538SGunnar Mills template <typename Callback>
157842cbe538SGunnar Mills void getPowerSupplyAttributes(
157942cbe538SGunnar Mills     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
158042cbe538SGunnar Mills     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
158142cbe538SGunnar Mills     Callback&& callback)
158242cbe538SGunnar Mills {
158362598e31SEd Tanous     BMCWEB_LOG_DEBUG("getPowerSupplyAttributes enter");
158442cbe538SGunnar Mills 
158542cbe538SGunnar Mills     // Only need the power supply attributes when the Power Schema
15860c728b42SJanet Adkins     if (sensorsAsyncResp->chassisSubNode != sensors::powerNodeStr)
158742cbe538SGunnar Mills     {
158862598e31SEd Tanous         BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit since not Power");
158942cbe538SGunnar Mills         callback(inventoryItems);
159042cbe538SGunnar Mills         return;
159142cbe538SGunnar Mills     }
159242cbe538SGunnar Mills 
1593e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
159442cbe538SGunnar Mills         "xyz.openbmc_project.Control.PowerSupplyAttributes"};
159542cbe538SGunnar Mills 
1596e99073f5SGeorge Liu     // Make call to ObjectMapper to find the PowerSupplyAttributes service
1597e99073f5SGeorge Liu     dbus::utility::getSubTree(
1598e99073f5SGeorge Liu         "/xyz/openbmc_project", 0, interfaces,
15998cb2c024SEd Tanous         [callback = std::forward<Callback>(callback), sensorsAsyncResp,
1600b9d36b47SEd Tanous          inventoryItems](
1601e99073f5SGeorge Liu             const boost::system::error_code& ec,
16024e0d8789SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
1603e99073f5SGeorge Liu             // Response handler for parsing output from GetSubTree
160462598e31SEd Tanous             BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler enter");
160542cbe538SGunnar Mills             if (ec)
160642cbe538SGunnar Mills             {
16078d1b46d7Szhanghch05                 messages::internalError(sensorsAsyncResp->asyncResp->res);
160862598e31SEd Tanous                 BMCWEB_LOG_ERROR(
160962598e31SEd Tanous                     "getPowerSupplyAttributes respHandler DBus error {}", ec);
161042cbe538SGunnar Mills                 return;
161142cbe538SGunnar Mills             }
161226f6976fSEd Tanous             if (subtree.empty())
161342cbe538SGunnar Mills             {
161462598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
161542cbe538SGunnar Mills                 callback(inventoryItems);
161642cbe538SGunnar Mills                 return;
161742cbe538SGunnar Mills             }
161842cbe538SGunnar Mills 
161942cbe538SGunnar Mills             // Currently we only support 1 power supply attribute, use this for
162042cbe538SGunnar Mills             // all the power supplies. Build map of object path to connection.
162142cbe538SGunnar Mills             // Assume just 1 connection and 1 path for now.
1622fe04d49cSNan Zhou             std::map<std::string, std::string> psAttributesConnections;
162342cbe538SGunnar Mills 
162442cbe538SGunnar Mills             if (subtree[0].first.empty() || subtree[0].second.empty())
162542cbe538SGunnar Mills             {
162662598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
162742cbe538SGunnar Mills                 callback(inventoryItems);
162842cbe538SGunnar Mills                 return;
162942cbe538SGunnar Mills             }
163042cbe538SGunnar Mills 
163142cbe538SGunnar Mills             const std::string& psAttributesPath = subtree[0].first;
163242cbe538SGunnar Mills             const std::string& connection = subtree[0].second.begin()->first;
163342cbe538SGunnar Mills 
163442cbe538SGunnar Mills             if (connection.empty())
163542cbe538SGunnar Mills             {
163662598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
163742cbe538SGunnar Mills                 callback(inventoryItems);
163842cbe538SGunnar Mills                 return;
163942cbe538SGunnar Mills             }
164042cbe538SGunnar Mills 
164142cbe538SGunnar Mills             psAttributesConnections[psAttributesPath] = connection;
164262598e31SEd Tanous             BMCWEB_LOG_DEBUG("Added mapping {} -> {}", psAttributesPath,
164362598e31SEd Tanous                              connection);
164442cbe538SGunnar Mills 
164542cbe538SGunnar Mills             getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems,
164642cbe538SGunnar Mills                                          psAttributesConnections,
164742cbe538SGunnar Mills                                          std::move(callback));
164862598e31SEd Tanous             BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler exit");
1649e99073f5SGeorge Liu         });
165062598e31SEd Tanous     BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit");
165142cbe538SGunnar Mills }
165242cbe538SGunnar Mills 
165342cbe538SGunnar Mills /**
1654adc4f0dbSShawn McCarney  * @brief Gets inventory items associated with sensors.
16558fb49dd6SShawn McCarney  *
16568fb49dd6SShawn McCarney  * Finds the inventory items that are associated with the specified sensors.
1657adc4f0dbSShawn McCarney  * Then gets D-Bus data for the inventory items, such as presence and VPD.
16588fb49dd6SShawn McCarney  *
1659adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
1660adc4f0dbSShawn McCarney  * response.
16618fb49dd6SShawn McCarney  *
1662adc4f0dbSShawn McCarney  * Finds the inventory items asynchronously.  Invokes callback when the
1663adc4f0dbSShawn McCarney  * inventory items have been obtained.
1664adc4f0dbSShawn McCarney  *
1665adc4f0dbSShawn McCarney  * The callback must have the following signature:
1666adc4f0dbSShawn McCarney  *   @code
1667adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1668adc4f0dbSShawn McCarney  *   @endcode
16698fb49dd6SShawn McCarney  *
16708fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
16718fb49dd6SShawn McCarney  * @param sensorNames All sensors within the current chassis.
16728fb49dd6SShawn McCarney  * implements ObjectManager.
1673adc4f0dbSShawn McCarney  * @param callback Callback to invoke when inventory items have been obtained.
16748fb49dd6SShawn McCarney  */
1675adc4f0dbSShawn McCarney template <typename Callback>
16764ff0f1f4SEd Tanous inline void
1677d0090733SEd Tanous     getInventoryItems(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1678fe04d49cSNan Zhou                       const std::shared_ptr<std::set<std::string>> sensorNames,
1679adc4f0dbSShawn McCarney                       Callback&& callback)
16808fb49dd6SShawn McCarney {
168162598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItems enter");
1682adc4f0dbSShawn McCarney     auto getInventoryItemAssociationsCb =
16838cb2c024SEd Tanous         [sensorsAsyncResp, callback = std::forward<Callback>(callback)](
16844e0d8789SEd Tanous             std::shared_ptr<std::vector<InventoryItem>>
16854e0d8789SEd Tanous                 inventoryItems) mutable {
168662598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb enter");
16878fb49dd6SShawn McCarney             auto getInventoryItemsConnectionsCb =
1688d0090733SEd Tanous                 [sensorsAsyncResp, inventoryItems,
16894e0d8789SEd Tanous                  callback = std::forward<Callback>(callback)](
16904e0d8789SEd Tanous                     std::shared_ptr<std::set<std::string>>
16914e0d8789SEd Tanous                         invConnections) mutable {
169262598e31SEd Tanous                     BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb enter");
1693bd79bce8SPatrick Williams                     auto getInventoryItemsDataCb =
1694bd79bce8SPatrick Williams                         [sensorsAsyncResp, inventoryItems,
16954e0d8789SEd Tanous                          callback =
16964e0d8789SEd Tanous                              std::forward<Callback>(callback)]() mutable {
169762598e31SEd Tanous                             BMCWEB_LOG_DEBUG("getInventoryItemsDataCb enter");
169842cbe538SGunnar Mills 
1699bd79bce8SPatrick Williams                             auto getInventoryLedsCb =
1700bd79bce8SPatrick Williams                                 [sensorsAsyncResp, inventoryItems,
17014e0d8789SEd Tanous                                  callback = std::forward<Callback>(
17024e0d8789SEd Tanous                                      callback)]() mutable {
1703bd79bce8SPatrick Williams                                     BMCWEB_LOG_DEBUG(
1704bd79bce8SPatrick Williams                                         "getInventoryLedsCb enter");
1705bd79bce8SPatrick Williams                                     // Find Power Supply Attributes and get the
1706bd79bce8SPatrick Williams                                     // data
1707bd79bce8SPatrick Williams                                     getPowerSupplyAttributes(
1708bd79bce8SPatrick Williams                                         sensorsAsyncResp, inventoryItems,
170942cbe538SGunnar Mills                                         std::move(callback));
171062598e31SEd Tanous                                     BMCWEB_LOG_DEBUG("getInventoryLedsCb exit");
171142cbe538SGunnar Mills                                 };
171242cbe538SGunnar Mills 
1713d500549bSAnthony Wilson                             // Find led connections and get the data
1714d500549bSAnthony Wilson                             getInventoryLeds(sensorsAsyncResp, inventoryItems,
171542cbe538SGunnar Mills                                              std::move(getInventoryLedsCb));
171662598e31SEd Tanous                             BMCWEB_LOG_DEBUG("getInventoryItemsDataCb exit");
1717d500549bSAnthony Wilson                         };
17188fb49dd6SShawn McCarney 
1719adc4f0dbSShawn McCarney                     // Get inventory item data from connections
1720adc4f0dbSShawn McCarney                     getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1721d0090733SEd Tanous                                           invConnections,
1722d500549bSAnthony Wilson                                           std::move(getInventoryItemsDataCb));
172362598e31SEd Tanous                     BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb exit");
17248fb49dd6SShawn McCarney                 };
17258fb49dd6SShawn McCarney 
1726adc4f0dbSShawn McCarney             // Get connections that provide inventory item data
1727bd79bce8SPatrick Williams             getInventoryItemsConnections(
1728bd79bce8SPatrick Williams                 sensorsAsyncResp, inventoryItems,
17298fb49dd6SShawn McCarney                 std::move(getInventoryItemsConnectionsCb));
173062598e31SEd Tanous             BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb exit");
17318fb49dd6SShawn McCarney         };
17328fb49dd6SShawn McCarney 
1733adc4f0dbSShawn McCarney     // Get associations from sensors to inventory items
1734d0090733SEd Tanous     getInventoryItemAssociations(sensorsAsyncResp, sensorNames,
1735adc4f0dbSShawn McCarney                                  std::move(getInventoryItemAssociationsCb));
173662598e31SEd Tanous     BMCWEB_LOG_DEBUG("getInventoryItems exit");
1737adc4f0dbSShawn McCarney }
1738adc4f0dbSShawn McCarney 
1739adc4f0dbSShawn McCarney /**
1740adc4f0dbSShawn McCarney  * @brief Returns JSON PowerSupply object for the specified inventory item.
1741adc4f0dbSShawn McCarney  *
1742adc4f0dbSShawn McCarney  * Searches for a JSON PowerSupply object that matches the specified inventory
1743adc4f0dbSShawn McCarney  * item.  If one is not found, a new PowerSupply object is added to the JSON
1744adc4f0dbSShawn McCarney  * array.
1745adc4f0dbSShawn McCarney  *
1746adc4f0dbSShawn McCarney  * Multiple sensors are often associated with one power supply inventory item.
1747adc4f0dbSShawn McCarney  * As a result, multiple sensor values are stored in one JSON PowerSupply
1748adc4f0dbSShawn McCarney  * object.
1749adc4f0dbSShawn McCarney  *
1750adc4f0dbSShawn McCarney  * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1751adc4f0dbSShawn McCarney  * @param inventoryItem Inventory item for the power supply.
1752adc4f0dbSShawn McCarney  * @param chassisId Chassis that contains the power supply.
1753adc4f0dbSShawn McCarney  * @return JSON PowerSupply object for the specified inventory item.
1754adc4f0dbSShawn McCarney  */
175523a21a1cSEd Tanous inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
1756adc4f0dbSShawn McCarney                                       const InventoryItem& inventoryItem,
1757adc4f0dbSShawn McCarney                                       const std::string& chassisId)
1758adc4f0dbSShawn McCarney {
175918f8f608SEd Tanous     std::string nameS;
17606f4bd290SAlexander Hansen     nameS.resize(inventoryItem.name.size());
176118f8f608SEd Tanous     std::ranges::replace_copy(inventoryItem.name, nameS.begin(), '_', ' ');
1762adc4f0dbSShawn McCarney     // Check if matching PowerSupply object already exists in JSON array
1763adc4f0dbSShawn McCarney     for (nlohmann::json& powerSupply : powerSupplyArray)
1764adc4f0dbSShawn McCarney     {
176518f8f608SEd Tanous         nlohmann::json::iterator nameIt = powerSupply.find("Name");
176618f8f608SEd Tanous         if (nameIt == powerSupply.end())
176718f8f608SEd Tanous         {
176818f8f608SEd Tanous             continue;
176918f8f608SEd Tanous         }
177018f8f608SEd Tanous         const std::string* name = nameIt->get_ptr<std::string*>();
177118f8f608SEd Tanous         if (name == nullptr)
177218f8f608SEd Tanous         {
177318f8f608SEd Tanous             continue;
177418f8f608SEd Tanous         }
177518f8f608SEd Tanous         if (nameS == *name)
1776adc4f0dbSShawn McCarney         {
1777adc4f0dbSShawn McCarney             return powerSupply;
1778adc4f0dbSShawn McCarney         }
1779adc4f0dbSShawn McCarney     }
1780adc4f0dbSShawn McCarney 
1781adc4f0dbSShawn McCarney     // Add new PowerSupply object to JSON array
1782adc4f0dbSShawn McCarney     powerSupplyArray.push_back({});
1783adc4f0dbSShawn McCarney     nlohmann::json& powerSupply = powerSupplyArray.back();
1784bd79bce8SPatrick Williams     boost::urls::url url =
1785bd79bce8SPatrick Williams         boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
1786eddfc437SWilly Tu     url.set_fragment(("/PowerSupplies"_json_pointer).to_string());
1787eddfc437SWilly Tu     powerSupply["@odata.id"] = std::move(url);
178818f8f608SEd Tanous     std::string escaped;
17896f4bd290SAlexander Hansen     escaped.resize(inventoryItem.name.size());
179018f8f608SEd Tanous     std::ranges::replace_copy(inventoryItem.name, escaped.begin(), '_', ' ');
179118f8f608SEd Tanous     powerSupply["Name"] = std::move(escaped);
1792adc4f0dbSShawn McCarney     powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1793adc4f0dbSShawn McCarney     powerSupply["Model"] = inventoryItem.model;
1794adc4f0dbSShawn McCarney     powerSupply["PartNumber"] = inventoryItem.partNumber;
1795adc4f0dbSShawn McCarney     powerSupply["SerialNumber"] = inventoryItem.serialNumber;
1796c9563608SJanet Adkins     sensor_utils::setLedState(powerSupply, &inventoryItem);
1797adc4f0dbSShawn McCarney 
179842cbe538SGunnar Mills     if (inventoryItem.powerSupplyEfficiencyPercent >= 0)
179942cbe538SGunnar Mills     {
180042cbe538SGunnar Mills         powerSupply["EfficiencyPercent"] =
180142cbe538SGunnar Mills             inventoryItem.powerSupplyEfficiencyPercent;
180242cbe538SGunnar Mills     }
180342cbe538SGunnar Mills 
1804c9563608SJanet Adkins     powerSupply["Status"]["State"] =
1805c9563608SJanet Adkins         sensor_utils::getState(&inventoryItem, true);
1806adc4f0dbSShawn McCarney     const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1807adc4f0dbSShawn McCarney     powerSupply["Status"]["Health"] = health;
1808adc4f0dbSShawn McCarney 
1809adc4f0dbSShawn McCarney     return powerSupply;
18108fb49dd6SShawn McCarney }
18118fb49dd6SShawn McCarney 
18128fb49dd6SShawn McCarney /**
1813de629b6eSShawn McCarney  * @brief Gets the values of the specified sensors.
1814de629b6eSShawn McCarney  *
1815de629b6eSShawn McCarney  * Stores the results as JSON in the SensorsAsyncResp.
1816de629b6eSShawn McCarney  *
1817de629b6eSShawn McCarney  * Gets the sensor values asynchronously.  Stores the results later when the
1818de629b6eSShawn McCarney  * information has been obtained.
1819de629b6eSShawn McCarney  *
1820adc4f0dbSShawn McCarney  * The sensorNames set contains all requested sensors for the current chassis.
1821de629b6eSShawn McCarney  *
1822de629b6eSShawn McCarney  * To minimize the number of DBus calls, the DBus method
1823de629b6eSShawn McCarney  * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1824de629b6eSShawn McCarney  * values of all sensors provided by a connection (service).
1825de629b6eSShawn McCarney  *
1826de629b6eSShawn McCarney  * The connections set contains all the connections that provide sensor values.
1827de629b6eSShawn McCarney  *
1828adc4f0dbSShawn McCarney  * The InventoryItem vector contains D-Bus inventory items associated with the
1829adc4f0dbSShawn McCarney  * sensors.  Inventory item data is needed for some Redfish sensor properties.
1830adc4f0dbSShawn McCarney  *
1831de629b6eSShawn McCarney  * @param SensorsAsyncResp Pointer to object holding response data.
1832adc4f0dbSShawn McCarney  * @param sensorNames All requested sensors within the current chassis.
1833de629b6eSShawn McCarney  * @param connections Connections that provide sensor values.
1834de629b6eSShawn McCarney  * implements ObjectManager.
1835adc4f0dbSShawn McCarney  * @param inventoryItems Inventory items associated with the sensors.
1836de629b6eSShawn McCarney  */
183723a21a1cSEd Tanous inline void getSensorData(
183881ce609eSEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1839fe04d49cSNan Zhou     const std::shared_ptr<std::set<std::string>>& sensorNames,
1840fe04d49cSNan Zhou     const std::set<std::string>& connections,
1841b5a76932SEd Tanous     const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems)
1842de629b6eSShawn McCarney {
184362598e31SEd Tanous     BMCWEB_LOG_DEBUG("getSensorData enter");
1844de629b6eSShawn McCarney     // Get managed objects from all services exposing sensors
1845de629b6eSShawn McCarney     for (const std::string& connection : connections)
1846de629b6eSShawn McCarney     {
18475eb468daSGeorge Liu         sdbusplus::message::object_path sensorPath(
18485eb468daSGeorge Liu             "/xyz/openbmc_project/sensors");
18495eb468daSGeorge Liu         dbus::utility::getManagedObjects(
18505eb468daSGeorge Liu             connection, sensorPath,
1851002d39b4SEd Tanous             [sensorsAsyncResp, sensorNames,
18525e7e2dc5SEd Tanous              inventoryItems](const boost::system::error_code& ec,
185302cad96eSEd Tanous                              const dbus::utility::ManagedObjectType& resp) {
185462598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getManagedObjectsCb enter");
1855de629b6eSShawn McCarney                 if (ec)
1856de629b6eSShawn McCarney                 {
185762598e31SEd Tanous                     BMCWEB_LOG_ERROR("getManagedObjectsCb DBUS error: {}", ec);
18588d1b46d7Szhanghch05                     messages::internalError(sensorsAsyncResp->asyncResp->res);
1859de629b6eSShawn McCarney                     return;
1860de629b6eSShawn McCarney                 }
18610c728b42SJanet Adkins                 auto chassisSubNode = sensor_utils::chassisSubNodeFromString(
18620c728b42SJanet Adkins                     sensorsAsyncResp->chassisSubNode);
1863de629b6eSShawn McCarney                 // Go through all objects and update response with sensor data
1864de629b6eSShawn McCarney                 for (const auto& objDictEntry : resp)
1865de629b6eSShawn McCarney                 {
1866de629b6eSShawn McCarney                     const std::string& objPath =
1867de629b6eSShawn McCarney                         static_cast<const std::string&>(objDictEntry.first);
186862598e31SEd Tanous                     BMCWEB_LOG_DEBUG("getManagedObjectsCb parsing object {}",
186962598e31SEd Tanous                                      objPath);
1870de629b6eSShawn McCarney 
1871de629b6eSShawn McCarney                     std::vector<std::string> split;
1872de629b6eSShawn McCarney                     // Reserve space for
1873de629b6eSShawn McCarney                     // /xyz/openbmc_project/sensors/<name>/<subname>
1874de629b6eSShawn McCarney                     split.reserve(6);
187550ebd4afSEd Tanous                     // NOLINTNEXTLINE
187650ebd4afSEd Tanous                     bmcweb::split(split, objPath, '/');
1877de629b6eSShawn McCarney                     if (split.size() < 6)
1878de629b6eSShawn McCarney                     {
187962598e31SEd Tanous                         BMCWEB_LOG_ERROR("Got path that isn't long enough {}",
188062598e31SEd Tanous                                          objPath);
1881de629b6eSShawn McCarney                         continue;
1882de629b6eSShawn McCarney                     }
188350ebd4afSEd Tanous                     // These indexes aren't intuitive, as split puts an empty
1884de629b6eSShawn McCarney                     // string at the beginning
1885de629b6eSShawn McCarney                     const std::string& sensorType = split[4];
1886de629b6eSShawn McCarney                     const std::string& sensorName = split[5];
188762598e31SEd Tanous                     BMCWEB_LOG_DEBUG("sensorName {} sensorType {}", sensorName,
188862598e31SEd Tanous                                      sensorType);
188949c53ac9SJohnathan Mantey                     if (sensorNames->find(objPath) == sensorNames->end())
1890de629b6eSShawn McCarney                     {
189162598e31SEd Tanous                         BMCWEB_LOG_DEBUG("{} not in sensor list ", sensorName);
1892de629b6eSShawn McCarney                         continue;
1893de629b6eSShawn McCarney                     }
1894de629b6eSShawn McCarney 
1895adc4f0dbSShawn McCarney                     // Find inventory item (if any) associated with sensor
1896adc4f0dbSShawn McCarney                     InventoryItem* inventoryItem =
1897adc4f0dbSShawn McCarney                         findInventoryItemForSensor(inventoryItems, objPath);
1898adc4f0dbSShawn McCarney 
189995a3ecadSAnthony Wilson                     const std::string& sensorSchema =
190081ce609eSEd Tanous                         sensorsAsyncResp->chassisSubNode;
190195a3ecadSAnthony Wilson 
190295a3ecadSAnthony Wilson                     nlohmann::json* sensorJson = nullptr;
190395a3ecadSAnthony Wilson 
19040c728b42SJanet Adkins                     if (sensorSchema == sensors::sensorsNodeStr &&
1905928fefb9SNan Zhou                         !sensorsAsyncResp->efficientExpand)
190695a3ecadSAnthony Wilson                     {
19071516c21bSJanet Adkins                         std::string sensorId =
19081516c21bSJanet Adkins                             redfish::sensor_utils::getSensorId(sensorName,
19091516c21bSJanet Adkins                                                                sensorType);
1910c1d019a6SEd Tanous 
1911bd79bce8SPatrick Williams                         sensorsAsyncResp->asyncResp->res
1912bd79bce8SPatrick Williams                             .jsonValue["@odata.id"] = boost::urls::format(
1913bd79bce8SPatrick Williams                             "/redfish/v1/Chassis/{}/{}/{}",
1914c1d019a6SEd Tanous                             sensorsAsyncResp->chassisId,
1915bd79bce8SPatrick Williams                             sensorsAsyncResp->chassisSubNode, sensorId);
1916bd79bce8SPatrick Williams                         sensorJson =
1917bd79bce8SPatrick Williams                             &(sensorsAsyncResp->asyncResp->res.jsonValue);
191895a3ecadSAnthony Wilson                     }
191995a3ecadSAnthony Wilson                     else
192095a3ecadSAnthony Wilson                     {
1921271584abSEd Tanous                         std::string fieldName;
1922928fefb9SNan Zhou                         if (sensorsAsyncResp->efficientExpand)
1923928fefb9SNan Zhou                         {
1924928fefb9SNan Zhou                             fieldName = "Members";
1925928fefb9SNan Zhou                         }
1926928fefb9SNan Zhou                         else if (sensorType == "temperature")
1927de629b6eSShawn McCarney                         {
1928de629b6eSShawn McCarney                             fieldName = "Temperatures";
1929de629b6eSShawn McCarney                         }
1930bd79bce8SPatrick Williams                         else if (sensorType == "fan" ||
1931bd79bce8SPatrick Williams                                  sensorType == "fan_tach" ||
1932de629b6eSShawn McCarney                                  sensorType == "fan_pwm")
1933de629b6eSShawn McCarney                         {
1934de629b6eSShawn McCarney                             fieldName = "Fans";
1935de629b6eSShawn McCarney                         }
1936de629b6eSShawn McCarney                         else if (sensorType == "voltage")
1937de629b6eSShawn McCarney                         {
1938de629b6eSShawn McCarney                             fieldName = "Voltages";
1939de629b6eSShawn McCarney                         }
1940de629b6eSShawn McCarney                         else if (sensorType == "power")
1941de629b6eSShawn McCarney                         {
194255f79e6fSEd Tanous                             if (sensorName == "total_power")
1943028f7ebcSEddie James                             {
1944028f7ebcSEddie James                                 fieldName = "PowerControl";
1945028f7ebcSEddie James                             }
1946adc4f0dbSShawn McCarney                             else if ((inventoryItem != nullptr) &&
1947adc4f0dbSShawn McCarney                                      (inventoryItem->isPowerSupply))
1948028f7ebcSEddie James                             {
1949de629b6eSShawn McCarney                                 fieldName = "PowerSupplies";
1950de629b6eSShawn McCarney                             }
1951adc4f0dbSShawn McCarney                             else
1952adc4f0dbSShawn McCarney                             {
1953adc4f0dbSShawn McCarney                                 // Other power sensors are in SensorCollection
1954adc4f0dbSShawn McCarney                                 continue;
1955adc4f0dbSShawn McCarney                             }
1956028f7ebcSEddie James                         }
1957de629b6eSShawn McCarney                         else
1958de629b6eSShawn McCarney                         {
1959bd79bce8SPatrick Williams                             BMCWEB_LOG_ERROR(
1960bd79bce8SPatrick Williams                                 "Unsure how to handle sensorType {}",
196162598e31SEd Tanous                                 sensorType);
1962de629b6eSShawn McCarney                             continue;
1963de629b6eSShawn McCarney                         }
1964de629b6eSShawn McCarney 
1965de629b6eSShawn McCarney                         nlohmann::json& tempArray =
1966bd79bce8SPatrick Williams                             sensorsAsyncResp->asyncResp->res
1967bd79bce8SPatrick Williams                                 .jsonValue[fieldName];
1968adc4f0dbSShawn McCarney                         if (fieldName == "PowerControl")
196949c53ac9SJohnathan Mantey                         {
1970adc4f0dbSShawn McCarney                             if (tempArray.empty())
19717ab06f49SGunnar Mills                             {
197295a3ecadSAnthony Wilson                                 // Put multiple "sensors" into a single
197395a3ecadSAnthony Wilson                                 // PowerControl. Follows MemberId naming and
197495a3ecadSAnthony Wilson                                 // naming in power.hpp.
19751476687dSEd Tanous                                 nlohmann::json::object_t power;
1976ef4c65b7SEd Tanous                                 boost::urls::url url = boost::urls::format(
1977ef4c65b7SEd Tanous                                     "/redfish/v1/Chassis/{}/{}",
1978eddfc437SWilly Tu                                     sensorsAsyncResp->chassisId,
1979eddfc437SWilly Tu                                     sensorsAsyncResp->chassisSubNode);
1980bd79bce8SPatrick Williams                                 url.set_fragment(
1981bd79bce8SPatrick Williams                                     (""_json_pointer / fieldName / "0")
1982eddfc437SWilly Tu                                         .to_string());
1983eddfc437SWilly Tu                                 power["@odata.id"] = std::move(url);
1984b2ba3072SPatrick Williams                                 tempArray.emplace_back(std::move(power));
1985adc4f0dbSShawn McCarney                             }
1986adc4f0dbSShawn McCarney                             sensorJson = &(tempArray.back());
1987adc4f0dbSShawn McCarney                         }
1988adc4f0dbSShawn McCarney                         else if (fieldName == "PowerSupplies")
1989adc4f0dbSShawn McCarney                         {
1990adc4f0dbSShawn McCarney                             if (inventoryItem != nullptr)
1991adc4f0dbSShawn McCarney                             {
1992bd79bce8SPatrick Williams                                 sensorJson = &(getPowerSupply(
1993bd79bce8SPatrick Williams                                     tempArray, *inventoryItem,
199481ce609eSEd Tanous                                     sensorsAsyncResp->chassisId));
1995adc4f0dbSShawn McCarney                             }
199649c53ac9SJohnathan Mantey                         }
1997928fefb9SNan Zhou                         else if (fieldName == "Members")
1998928fefb9SNan Zhou                         {
19991516c21bSJanet Adkins                             std::string sensorId =
20001516c21bSJanet Adkins                                 redfish::sensor_utils::getSensorId(sensorName,
20011516c21bSJanet Adkins                                                                    sensorType);
2002677bb756SEd Tanous 
20031476687dSEd Tanous                             nlohmann::json::object_t member;
2004ef4c65b7SEd Tanous                             member["@odata.id"] = boost::urls::format(
2005ef4c65b7SEd Tanous                                 "/redfish/v1/Chassis/{}/{}/{}",
2006677bb756SEd Tanous                                 sensorsAsyncResp->chassisId,
2007677bb756SEd Tanous                                 sensorsAsyncResp->chassisSubNode, sensorId);
2008b2ba3072SPatrick Williams                             tempArray.emplace_back(std::move(member));
2009928fefb9SNan Zhou                             sensorJson = &(tempArray.back());
2010928fefb9SNan Zhou                         }
201149c53ac9SJohnathan Mantey                         else
201249c53ac9SJohnathan Mantey                         {
20131476687dSEd Tanous                             nlohmann::json::object_t member;
2014ef4c65b7SEd Tanous                             boost::urls::url url = boost::urls::format(
2015ef4c65b7SEd Tanous                                 "/redfish/v1/Chassis/{}/{}",
2016eddfc437SWilly Tu                                 sensorsAsyncResp->chassisId,
2017eddfc437SWilly Tu                                 sensorsAsyncResp->chassisSubNode);
2018eddfc437SWilly Tu                             url.set_fragment(
2019eddfc437SWilly Tu                                 (""_json_pointer / fieldName).to_string());
2020eddfc437SWilly Tu                             member["@odata.id"] = std::move(url);
2021b2ba3072SPatrick Williams                             tempArray.emplace_back(std::move(member));
2022adc4f0dbSShawn McCarney                             sensorJson = &(tempArray.back());
202349c53ac9SJohnathan Mantey                         }
202495a3ecadSAnthony Wilson                     }
2025de629b6eSShawn McCarney 
2026adc4f0dbSShawn McCarney                     if (sensorJson != nullptr)
2027adc4f0dbSShawn McCarney                     {
20280c728b42SJanet Adkins                         objectInterfacesToJson(
20290c728b42SJanet Adkins                             sensorName, sensorType, chassisSubNode,
20300c728b42SJanet Adkins                             objDictEntry.second, *sensorJson, inventoryItem);
20311d7c0054SEd Tanous 
20321d7c0054SEd Tanous                         std::string path = "/xyz/openbmc_project/sensors/";
20331d7c0054SEd Tanous                         path += sensorType;
20341d7c0054SEd Tanous                         path += "/";
20351d7c0054SEd Tanous                         path += sensorName;
2036c1d019a6SEd Tanous                         sensorsAsyncResp->addMetadata(*sensorJson, path);
2037adc4f0dbSShawn McCarney                     }
2038de629b6eSShawn McCarney                 }
203981ce609eSEd Tanous                 if (sensorsAsyncResp.use_count() == 1)
204049c53ac9SJohnathan Mantey                 {
204181ce609eSEd Tanous                     sortJSONResponse(sensorsAsyncResp);
20420c728b42SJanet Adkins                     if (chassisSubNode ==
20430c728b42SJanet Adkins                             sensor_utils::ChassisSubNode::sensorsNode &&
2044928fefb9SNan Zhou                         sensorsAsyncResp->efficientExpand)
2045928fefb9SNan Zhou                     {
2046928fefb9SNan Zhou                         sensorsAsyncResp->asyncResp->res
2047928fefb9SNan Zhou                             .jsonValue["Members@odata.count"] =
2048bd79bce8SPatrick Williams                             sensorsAsyncResp->asyncResp->res
2049bd79bce8SPatrick Williams                                 .jsonValue["Members"]
2050928fefb9SNan Zhou                                 .size();
2051928fefb9SNan Zhou                     }
20520c728b42SJanet Adkins                     else if (chassisSubNode ==
20530c728b42SJanet Adkins                              sensor_utils::ChassisSubNode::thermalNode)
20548bd25ccdSJames Feist                     {
205581ce609eSEd Tanous                         populateFanRedundancy(sensorsAsyncResp);
20568bd25ccdSJames Feist                     }
205749c53ac9SJohnathan Mantey                 }
205862598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getManagedObjectsCb exit");
20595eb468daSGeorge Liu             });
206023a21a1cSEd Tanous     }
206162598e31SEd Tanous     BMCWEB_LOG_DEBUG("getSensorData exit");
2062de629b6eSShawn McCarney }
2063de629b6eSShawn McCarney 
2064fe04d49cSNan Zhou inline void
2065fe04d49cSNan Zhou     processSensorList(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
2066fe04d49cSNan Zhou                       const std::shared_ptr<std::set<std::string>>& sensorNames)
20671abe55efSEd Tanous {
2068fe04d49cSNan Zhou     auto getConnectionCb = [sensorsAsyncResp, sensorNames](
2069fe04d49cSNan Zhou                                const std::set<std::string>& connections) {
207062598e31SEd Tanous         BMCWEB_LOG_DEBUG("getConnectionCb enter");
2071adc4f0dbSShawn McCarney         auto getInventoryItemsCb =
2072bd79bce8SPatrick Williams             [sensorsAsyncResp, sensorNames, connections](
2073bd79bce8SPatrick Williams                 const std::shared_ptr<std::vector<InventoryItem>>&
20744e0d8789SEd Tanous                     inventoryItems) mutable {
207562598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryItemsCb enter");
207649c53ac9SJohnathan Mantey                 // Get sensor data and store results in JSON
2077002d39b4SEd Tanous                 getSensorData(sensorsAsyncResp, sensorNames, connections,
2078d0090733SEd Tanous                               inventoryItems);
207962598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getInventoryItemsCb exit");
2080adc4f0dbSShawn McCarney             };
2081adc4f0dbSShawn McCarney 
2082adc4f0dbSShawn McCarney         // Get inventory items associated with sensors
2083d0090733SEd Tanous         getInventoryItems(sensorsAsyncResp, sensorNames,
2084adc4f0dbSShawn McCarney                           std::move(getInventoryItemsCb));
2085adc4f0dbSShawn McCarney 
208662598e31SEd Tanous         BMCWEB_LOG_DEBUG("getConnectionCb exit");
208708777fb0SLewanczyk, Dawid     };
2088de629b6eSShawn McCarney 
2089de629b6eSShawn McCarney     // Get set of connections that provide sensor values
209081ce609eSEd Tanous     getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb));
209195a3ecadSAnthony Wilson }
209295a3ecadSAnthony Wilson 
209395a3ecadSAnthony Wilson /**
209495a3ecadSAnthony Wilson  * @brief Entry point for retrieving sensors data related to requested
209595a3ecadSAnthony Wilson  *        chassis.
209695a3ecadSAnthony Wilson  * @param SensorsAsyncResp   Pointer to object holding response data
209795a3ecadSAnthony Wilson  */
2098b5a76932SEd Tanous inline void
209981ce609eSEd Tanous     getChassisData(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
210095a3ecadSAnthony Wilson {
210162598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassisData enter");
210295a3ecadSAnthony Wilson     auto getChassisCb =
210381ce609eSEd Tanous         [sensorsAsyncResp](
2104fe04d49cSNan Zhou             const std::shared_ptr<std::set<std::string>>& sensorNames) {
210562598e31SEd Tanous             BMCWEB_LOG_DEBUG("getChassisCb enter");
210681ce609eSEd Tanous             processSensorList(sensorsAsyncResp, sensorNames);
210762598e31SEd Tanous             BMCWEB_LOG_DEBUG("getChassisCb exit");
210808777fb0SLewanczyk, Dawid         };
2109928fefb9SNan Zhou     // SensorCollection doesn't contain the Redundancy property
21100c728b42SJanet Adkins     if (sensorsAsyncResp->chassisSubNode != sensors::sensorsNodeStr)
2111928fefb9SNan Zhou     {
21128d1b46d7Szhanghch05         sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
21138d1b46d7Szhanghch05             nlohmann::json::array();
2114928fefb9SNan Zhou     }
211526f03899SShawn McCarney     // Get set of sensors in chassis
21167f1cc26dSEd Tanous     getChassis(sensorsAsyncResp->asyncResp, sensorsAsyncResp->chassisId,
21177f1cc26dSEd Tanous                sensorsAsyncResp->chassisSubNode, sensorsAsyncResp->types,
21187f1cc26dSEd Tanous                std::move(getChassisCb));
211962598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassisData exit");
2120271584abSEd Tanous }
212108777fb0SLewanczyk, Dawid 
2122413961deSRichard Marian Thomaiyar /**
212349c53ac9SJohnathan Mantey  * @brief Find the requested sensorName in the list of all sensors supplied by
212449c53ac9SJohnathan Mantey  * the chassis node
212549c53ac9SJohnathan Mantey  *
212649c53ac9SJohnathan Mantey  * @param sensorName   The sensor name supplied in the PATCH request
212749c53ac9SJohnathan Mantey  * @param sensorsList  The list of sensors managed by the chassis node
212849c53ac9SJohnathan Mantey  * @param sensorsModified  The list of sensors that were found as a result of
212949c53ac9SJohnathan Mantey  *                         repeated calls to this function
213049c53ac9SJohnathan Mantey  */
2131bd79bce8SPatrick Williams inline bool findSensorNameUsingSensorPath(
2132bd79bce8SPatrick Williams     std::string_view sensorName, const std::set<std::string>& sensorsList,
2133fe04d49cSNan Zhou     std::set<std::string>& sensorsModified)
213449c53ac9SJohnathan Mantey {
2135fe04d49cSNan Zhou     for (const auto& chassisSensor : sensorsList)
213649c53ac9SJohnathan Mantey     {
213728aa8de5SGeorge Liu         sdbusplus::message::object_path path(chassisSensor);
2138b00dcc27SEd Tanous         std::string thisSensorName = path.filename();
213928aa8de5SGeorge Liu         if (thisSensorName.empty())
214049c53ac9SJohnathan Mantey         {
214149c53ac9SJohnathan Mantey             continue;
214249c53ac9SJohnathan Mantey         }
214349c53ac9SJohnathan Mantey         if (thisSensorName == sensorName)
214449c53ac9SJohnathan Mantey         {
214549c53ac9SJohnathan Mantey             sensorsModified.emplace(chassisSensor);
214649c53ac9SJohnathan Mantey             return true;
214749c53ac9SJohnathan Mantey         }
214849c53ac9SJohnathan Mantey     }
214949c53ac9SJohnathan Mantey     return false;
215049c53ac9SJohnathan Mantey }
215149c53ac9SJohnathan Mantey 
215249c53ac9SJohnathan Mantey /**
2153413961deSRichard Marian Thomaiyar  * @brief Entry point for overriding sensor values of given sensor
2154413961deSRichard Marian Thomaiyar  *
21558d1b46d7Szhanghch05  * @param sensorAsyncResp   response object
21564bb3dc34SCarol Wang  * @param allCollections   Collections extract from sensors' request patch info
2157413961deSRichard Marian Thomaiyar  * @param chassisSubNode   Chassis Node for which the query has to happen
2158413961deSRichard Marian Thomaiyar  */
215923a21a1cSEd Tanous inline void setSensorsOverride(
2160b5a76932SEd Tanous     const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
21610885057cSEd Tanous     std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>&
2162397fd61fSjayaprakash Mutyala         allCollections)
2163413961deSRichard Marian Thomaiyar {
216462598e31SEd Tanous     BMCWEB_LOG_INFO("setSensorsOverride for subNode{}",
216562598e31SEd Tanous                     sensorAsyncResp->chassisSubNode);
2166413961deSRichard Marian Thomaiyar 
2167d02aad39SEd Tanous     std::string_view propertyValueName;
2168f65af9e8SRichard Marian Thomaiyar     std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
2169413961deSRichard Marian Thomaiyar     std::string memberId;
2170543f4400SEd Tanous     double value = 0.0;
2171f65af9e8SRichard Marian Thomaiyar     for (auto& collectionItems : allCollections)
2172f65af9e8SRichard Marian Thomaiyar     {
2173f65af9e8SRichard Marian Thomaiyar         if (collectionItems.first == "Temperatures")
2174f65af9e8SRichard Marian Thomaiyar         {
2175f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingCelsius";
2176f65af9e8SRichard Marian Thomaiyar         }
2177f65af9e8SRichard Marian Thomaiyar         else if (collectionItems.first == "Fans")
2178f65af9e8SRichard Marian Thomaiyar         {
2179f65af9e8SRichard Marian Thomaiyar             propertyValueName = "Reading";
2180f65af9e8SRichard Marian Thomaiyar         }
2181f65af9e8SRichard Marian Thomaiyar         else
2182f65af9e8SRichard Marian Thomaiyar         {
2183f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingVolts";
2184f65af9e8SRichard Marian Thomaiyar         }
2185f65af9e8SRichard Marian Thomaiyar         for (auto& item : collectionItems.second)
2186f65af9e8SRichard Marian Thomaiyar         {
2187afc474aeSMyung Bae             if (!json_util::readJsonObject( //
2188afc474aeSMyung Bae                     item, sensorAsyncResp->asyncResp->res, //
2189afc474aeSMyung Bae                     "MemberId", memberId, //
2190afc474aeSMyung Bae                     propertyValueName, value //
2191afc474aeSMyung Bae                     ))
2192413961deSRichard Marian Thomaiyar             {
2193413961deSRichard Marian Thomaiyar                 return;
2194413961deSRichard Marian Thomaiyar             }
2195f65af9e8SRichard Marian Thomaiyar             overrideMap.emplace(memberId,
2196f65af9e8SRichard Marian Thomaiyar                                 std::make_pair(value, collectionItems.first));
2197f65af9e8SRichard Marian Thomaiyar         }
2198f65af9e8SRichard Marian Thomaiyar     }
21994bb3dc34SCarol Wang 
2200bd79bce8SPatrick Williams     auto getChassisSensorListCb = [sensorAsyncResp, overrideMap,
2201bd79bce8SPatrick Williams                                    propertyValueNameStr =
2202bd79bce8SPatrick Williams                                        std::string(propertyValueName)](
2203bd79bce8SPatrick Williams                                       const std::shared_ptr<
2204bd79bce8SPatrick Williams                                           std::set<std::string>>& sensorsList) {
220549c53ac9SJohnathan Mantey         // Match sensor names in the PATCH request to those managed by the
220649c53ac9SJohnathan Mantey         // chassis node
2207fe04d49cSNan Zhou         const std::shared_ptr<std::set<std::string>> sensorNames =
2208fe04d49cSNan Zhou             std::make_shared<std::set<std::string>>();
2209f65af9e8SRichard Marian Thomaiyar         for (const auto& item : overrideMap)
2210413961deSRichard Marian Thomaiyar         {
2211f65af9e8SRichard Marian Thomaiyar             const auto& sensor = item.first;
2212c71d6125SEd Tanous             std::pair<std::string, std::string> sensorNameType =
22131516c21bSJanet Adkins                 redfish::sensor_utils::splitSensorNameAndType(sensor);
2214c71d6125SEd Tanous             if (!findSensorNameUsingSensorPath(sensorNameType.second,
2215c71d6125SEd Tanous                                                *sensorsList, *sensorNames))
2216f65af9e8SRichard Marian Thomaiyar             {
221762598e31SEd Tanous                 BMCWEB_LOG_INFO("Unable to find memberId {}", item.first);
22188d1b46d7Szhanghch05                 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
2219f65af9e8SRichard Marian Thomaiyar                                            item.second.second, item.first);
2220413961deSRichard Marian Thomaiyar                 return;
2221413961deSRichard Marian Thomaiyar             }
2222f65af9e8SRichard Marian Thomaiyar         }
2223413961deSRichard Marian Thomaiyar         // Get the connection to which the memberId belongs
2224bd79bce8SPatrick Williams         auto getObjectsWithConnectionCb = [sensorAsyncResp, overrideMap,
2225bd79bce8SPatrick Williams                                            propertyValueNameStr](
2226bd79bce8SPatrick Williams                                               const std::set<
2227bd79bce8SPatrick Williams                                                   std::string>& /*connections*/,
2228bd79bce8SPatrick Williams                                               const std::set<std::pair<
2229bd79bce8SPatrick Williams                                                   std::string, std::string>>&
2230413961deSRichard Marian Thomaiyar                                                   objectsWithConnection) {
2231f65af9e8SRichard Marian Thomaiyar             if (objectsWithConnection.size() != overrideMap.size())
2232413961deSRichard Marian Thomaiyar             {
223362598e31SEd Tanous                 BMCWEB_LOG_INFO(
223462598e31SEd Tanous                     "Unable to find all objects with proper connection {} requested {}",
223562598e31SEd Tanous                     objectsWithConnection.size(), overrideMap.size());
2236bd79bce8SPatrick Williams                 messages::resourceNotFound(
2237bd79bce8SPatrick Williams                     sensorAsyncResp->asyncResp->res,
22380c728b42SJanet Adkins                     sensorAsyncResp->chassisSubNode == sensors::thermalNodeStr
2239413961deSRichard Marian Thomaiyar                         ? "Temperatures"
2240413961deSRichard Marian Thomaiyar                         : "Voltages",
2241f65af9e8SRichard Marian Thomaiyar                     "Count");
2242f65af9e8SRichard Marian Thomaiyar                 return;
2243f65af9e8SRichard Marian Thomaiyar             }
2244f65af9e8SRichard Marian Thomaiyar             for (const auto& item : objectsWithConnection)
2245f65af9e8SRichard Marian Thomaiyar             {
224628aa8de5SGeorge Liu                 sdbusplus::message::object_path path(item.first);
224728aa8de5SGeorge Liu                 std::string sensorName = path.filename();
224828aa8de5SGeorge Liu                 if (sensorName.empty())
2249f65af9e8SRichard Marian Thomaiyar                 {
22504f277b54SJayaprakash Mutyala                     messages::internalError(sensorAsyncResp->asyncResp->res);
2251f65af9e8SRichard Marian Thomaiyar                     return;
2252f65af9e8SRichard Marian Thomaiyar                 }
22531516c21bSJanet Adkins                 std::string id = redfish::sensor_utils::getSensorId(
22541516c21bSJanet Adkins                     sensorName, path.parent_path().filename());
2255f65af9e8SRichard Marian Thomaiyar 
22563f5eb755SBan Feng                 const auto& iterator = overrideMap.find(id);
2257f65af9e8SRichard Marian Thomaiyar                 if (iterator == overrideMap.end())
2258f65af9e8SRichard Marian Thomaiyar                 {
225962598e31SEd Tanous                     BMCWEB_LOG_INFO("Unable to find sensor object{}",
226062598e31SEd Tanous                                     item.first);
22614f277b54SJayaprakash Mutyala                     messages::internalError(sensorAsyncResp->asyncResp->res);
2262413961deSRichard Marian Thomaiyar                     return;
2263413961deSRichard Marian Thomaiyar                 }
2264e93abac6SGinu George                 setDbusProperty(sensorAsyncResp->asyncResp,
2265e93abac6SGinu George                                 propertyValueNameStr, item.second, item.first,
2266e93abac6SGinu George                                 "xyz.openbmc_project.Sensor.Value", "Value",
2267d02aad39SEd Tanous                                 iterator->second.first);
2268f65af9e8SRichard Marian Thomaiyar             }
2269413961deSRichard Marian Thomaiyar         };
2270413961deSRichard Marian Thomaiyar         // Get object with connection for the given sensor name
2271413961deSRichard Marian Thomaiyar         getObjectsWithConnection(sensorAsyncResp, sensorNames,
2272413961deSRichard Marian Thomaiyar                                  std::move(getObjectsWithConnectionCb));
2273413961deSRichard Marian Thomaiyar     };
2274413961deSRichard Marian Thomaiyar     // get full sensor list for the given chassisId and cross verify the sensor.
22757f1cc26dSEd Tanous     getChassis(sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId,
22767f1cc26dSEd Tanous                sensorAsyncResp->chassisSubNode, sensorAsyncResp->types,
22777f1cc26dSEd Tanous                std::move(getChassisSensorListCb));
2278413961deSRichard Marian Thomaiyar }
2279413961deSRichard Marian Thomaiyar 
2280a0ec28b6SAdrian Ambrożewicz /**
2281a0ec28b6SAdrian Ambrożewicz  * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus
2282a0ec28b6SAdrian Ambrożewicz  * path of the sensor.
2283a0ec28b6SAdrian Ambrożewicz  *
2284a0ec28b6SAdrian Ambrożewicz  * Function builds valid Redfish response for sensor query of given chassis and
2285a0ec28b6SAdrian Ambrożewicz  * node. It then builds metadata about Redfish<->D-Bus correlations and provides
2286a0ec28b6SAdrian Ambrożewicz  * it to caller in a callback.
2287a0ec28b6SAdrian Ambrożewicz  *
2288a0ec28b6SAdrian Ambrożewicz  * @param chassis   Chassis for which retrieval should be performed
2289c9563608SJanet Adkins  * @param node  Node (group) of sensors. See sensor_utils::node for supported
2290c9563608SJanet Adkins  * values
2291a0ec28b6SAdrian Ambrożewicz  * @param mapComplete   Callback to be called with retrieval result
2292a0ec28b6SAdrian Ambrożewicz  */
2293931edc79SEd Tanous template <typename Callback>
2294bd79bce8SPatrick Williams inline void retrieveUriToDbusMap(
2295bd79bce8SPatrick Williams     const std::string& chassis, const std::string& node, Callback&& mapComplete)
2296a0ec28b6SAdrian Ambrożewicz {
229702da7c5aSEd Tanous     decltype(sensors::paths)::const_iterator pathIt =
229802da7c5aSEd Tanous         std::find_if(sensors::paths.cbegin(), sensors::paths.cend(),
229902da7c5aSEd Tanous                      [&node](auto&& val) { return val.first == node; });
230002da7c5aSEd Tanous     if (pathIt == sensors::paths.cend())
2301a0ec28b6SAdrian Ambrożewicz     {
230262598e31SEd Tanous         BMCWEB_LOG_ERROR("Wrong node provided : {}", node);
23036804b5c8SEd Tanous         std::map<std::string, std::string> noop;
23046804b5c8SEd Tanous         mapComplete(boost::beast::http::status::bad_request, noop);
2305a0ec28b6SAdrian Ambrożewicz         return;
2306a0ec28b6SAdrian Ambrożewicz     }
2307d51e072fSKrzysztof Grobelny 
230872374eb7SNan Zhou     auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
2309bd79bce8SPatrick Williams     auto callback =
2310bd79bce8SPatrick Williams         [asyncResp, mapCompleteCb = std::forward<Callback>(mapComplete)](
2311a0ec28b6SAdrian Ambrożewicz             const boost::beast::http::status status,
2312fe04d49cSNan Zhou             const std::map<std::string, std::string>& uriToDbus) {
2313fe04d49cSNan Zhou             mapCompleteCb(status, uriToDbus);
2314fe04d49cSNan Zhou         };
2315a0ec28b6SAdrian Ambrożewicz 
2316a0ec28b6SAdrian Ambrożewicz     auto resp = std::make_shared<SensorsAsyncResp>(
2317d51e072fSKrzysztof Grobelny         asyncResp, chassis, pathIt->second, node, std::move(callback));
2318a0ec28b6SAdrian Ambrożewicz     getChassisData(resp);
2319a0ec28b6SAdrian Ambrożewicz }
2320a0ec28b6SAdrian Ambrożewicz 
2321bacb2162SNan Zhou namespace sensors
2322bacb2162SNan Zhou {
2323928fefb9SNan Zhou 
2324bacb2162SNan Zhou inline void getChassisCallback(
2325c1d019a6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2326c1d019a6SEd Tanous     std::string_view chassisId, std::string_view chassisSubNode,
2327fe04d49cSNan Zhou     const std::shared_ptr<std::set<std::string>>& sensorNames)
2328bacb2162SNan Zhou {
232962598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassisCallback enter ");
2330bacb2162SNan Zhou 
2331c1d019a6SEd Tanous     nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
2332c1d019a6SEd Tanous     for (const std::string& sensor : *sensorNames)
2333bacb2162SNan Zhou     {
233462598e31SEd Tanous         BMCWEB_LOG_DEBUG("Adding sensor: {}", sensor);
2335bacb2162SNan Zhou 
2336bacb2162SNan Zhou         sdbusplus::message::object_path path(sensor);
2337bacb2162SNan Zhou         std::string sensorName = path.filename();
2338bacb2162SNan Zhou         if (sensorName.empty())
2339bacb2162SNan Zhou         {
234062598e31SEd Tanous             BMCWEB_LOG_ERROR("Invalid sensor path: {}", sensor);
2341c1d019a6SEd Tanous             messages::internalError(asyncResp->res);
2342bacb2162SNan Zhou             return;
2343bacb2162SNan Zhou         }
2344c1d019a6SEd Tanous         std::string type = path.parent_path().filename();
23451516c21bSJanet Adkins         std::string id = redfish::sensor_utils::getSensorId(sensorName, type);
2346c1d019a6SEd Tanous 
23471476687dSEd Tanous         nlohmann::json::object_t member;
2348ef4c65b7SEd Tanous         member["@odata.id"] = boost::urls::format(
2349ef4c65b7SEd Tanous             "/redfish/v1/Chassis/{}/{}/{}", chassisId, chassisSubNode, id);
2350c1d019a6SEd Tanous 
2351b2ba3072SPatrick Williams         entriesArray.emplace_back(std::move(member));
2352bacb2162SNan Zhou     }
2353bacb2162SNan Zhou 
2354c1d019a6SEd Tanous     asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
235562598e31SEd Tanous     BMCWEB_LOG_DEBUG("getChassisCallback exit");
2356bacb2162SNan Zhou }
2357e6bd846dSNan Zhou 
2358ac106bf6SEd Tanous inline void handleSensorCollectionGet(
2359ac106bf6SEd Tanous     App& app, const crow::Request& req,
2360ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2361de167a6fSNan Zhou     const std::string& chassisId)
2362de167a6fSNan Zhou {
2363de167a6fSNan Zhou     query_param::QueryCapabilities capabilities = {
2364de167a6fSNan Zhou         .canDelegateExpandLevel = 1,
2365de167a6fSNan Zhou     };
2366de167a6fSNan Zhou     query_param::Query delegatedQuery;
2367ac106bf6SEd Tanous     if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
2368de167a6fSNan Zhou                                                   delegatedQuery, capabilities))
2369de167a6fSNan Zhou     {
2370de167a6fSNan Zhou         return;
2371de167a6fSNan Zhou     }
2372de167a6fSNan Zhou 
2373de167a6fSNan Zhou     if (delegatedQuery.expandType != query_param::ExpandType::None)
2374de167a6fSNan Zhou     {
2375de167a6fSNan Zhou         // we perform efficient expand.
2376ac106bf6SEd Tanous         auto sensorsAsyncResp = std::make_shared<SensorsAsyncResp>(
2377ac106bf6SEd Tanous             asyncResp, chassisId, sensors::dbus::sensorPaths,
23780c728b42SJanet Adkins             sensors::sensorsNodeStr,
2379de167a6fSNan Zhou             /*efficientExpand=*/true);
2380ac106bf6SEd Tanous         getChassisData(sensorsAsyncResp);
2381de167a6fSNan Zhou 
238262598e31SEd Tanous         BMCWEB_LOG_DEBUG(
238362598e31SEd Tanous             "SensorCollection doGet exit via efficient expand handler");
2384de167a6fSNan Zhou         return;
23850bad320cSEd Tanous     }
2386de167a6fSNan Zhou 
2387de167a6fSNan Zhou     // We get all sensors as hyperlinkes in the chassis (this
2388de167a6fSNan Zhou     // implies we reply on the default query parameters handler)
23890c728b42SJanet Adkins     getChassis(asyncResp, chassisId, sensors::sensorsNodeStr, dbus::sensorPaths,
2390ac106bf6SEd Tanous                std::bind_front(sensors::getChassisCallback, asyncResp,
23910c728b42SJanet Adkins                                chassisId, sensors::sensorsNodeStr));
2392c1d019a6SEd Tanous }
23937f1cc26dSEd Tanous 
2394c1d019a6SEd Tanous inline void
2395c1d019a6SEd Tanous     getSensorFromDbus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2396c1d019a6SEd Tanous                       const std::string& sensorPath,
2397c1d019a6SEd Tanous                       const ::dbus::utility::MapperGetObject& mapperResponse)
2398c1d019a6SEd Tanous {
2399c1d019a6SEd Tanous     if (mapperResponse.size() != 1)
2400c1d019a6SEd Tanous     {
2401c1d019a6SEd Tanous         messages::internalError(asyncResp->res);
2402c1d019a6SEd Tanous         return;
2403c1d019a6SEd Tanous     }
2404c1d019a6SEd Tanous     const auto& valueIface = *mapperResponse.begin();
2405c1d019a6SEd Tanous     const std::string& connectionName = valueIface.first;
240662598e31SEd Tanous     BMCWEB_LOG_DEBUG("Looking up {}", connectionName);
240762598e31SEd Tanous     BMCWEB_LOG_DEBUG("Path {}", sensorPath);
2408c1343bf6SKrzysztof Grobelny 
2409*deae6a78SEd Tanous     ::dbus::utility::getAllProperties(
2410c1343bf6SKrzysztof Grobelny         *crow::connections::systemBus, connectionName, sensorPath, "",
2411c1d019a6SEd Tanous         [asyncResp,
24125e7e2dc5SEd Tanous          sensorPath](const boost::system::error_code& ec,
2413c1d019a6SEd Tanous                      const ::dbus::utility::DBusPropertiesMap& valuesDict) {
2414c1d019a6SEd Tanous             if (ec)
2415c1d019a6SEd Tanous             {
2416c1d019a6SEd Tanous                 messages::internalError(asyncResp->res);
2417c1d019a6SEd Tanous                 return;
2418c1d019a6SEd Tanous             }
2419c1d019a6SEd Tanous             sdbusplus::message::object_path path(sensorPath);
2420c1d019a6SEd Tanous             std::string name = path.filename();
2421c1d019a6SEd Tanous             path = path.parent_path();
2422c1d019a6SEd Tanous             std::string type = path.filename();
2423c9563608SJanet Adkins             sensor_utils::objectPropertiesToJson(
24240c728b42SJanet Adkins                 name, type, sensor_utils::ChassisSubNode::sensorsNode,
24250c728b42SJanet Adkins                 valuesDict, asyncResp->res.jsonValue, nullptr);
2426c1343bf6SKrzysztof Grobelny         });
2427de167a6fSNan Zhou }
2428de167a6fSNan Zhou 
2429e6bd846dSNan Zhou inline void handleSensorGet(App& app, const crow::Request& req,
2430c1d019a6SEd Tanous                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2431677bb756SEd Tanous                             const std::string& chassisId,
2432c1d019a6SEd Tanous                             const std::string& sensorId)
2433e6bd846dSNan Zhou {
2434c1d019a6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2435e6bd846dSNan Zhou     {
2436e6bd846dSNan Zhou         return;
2437e6bd846dSNan Zhou     }
2438c71d6125SEd Tanous     std::pair<std::string, std::string> nameType =
24391516c21bSJanet Adkins         redfish::sensor_utils::splitSensorNameAndType(sensorId);
2440c71d6125SEd Tanous     if (nameType.first.empty() || nameType.second.empty())
2441c1d019a6SEd Tanous     {
2442c1d019a6SEd Tanous         messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2443c1d019a6SEd Tanous         return;
2444c1d019a6SEd Tanous     }
2445c71d6125SEd Tanous 
2446ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2447ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/Sensors/{}", chassisId, sensorId);
2448c1d019a6SEd Tanous 
244962598e31SEd Tanous     BMCWEB_LOG_DEBUG("Sensor doGet enter");
2450e6bd846dSNan Zhou 
24512b73119cSGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
2452e6bd846dSNan Zhou         "xyz.openbmc_project.Sensor.Value"};
2453c71d6125SEd Tanous     std::string sensorPath = "/xyz/openbmc_project/sensors/" + nameType.first +
2454c71d6125SEd Tanous                              '/' + nameType.second;
2455e6bd846dSNan Zhou     // Get a list of all of the sensors that implement Sensor.Value
2456e6bd846dSNan Zhou     // and get the path and service name associated with the sensor
24572b73119cSGeorge Liu     ::dbus::utility::getDbusObject(
24582b73119cSGeorge Liu         sensorPath, interfaces,
2459aec0ec30SMyung Bae         [asyncResp, sensorId,
24602b73119cSGeorge Liu          sensorPath](const boost::system::error_code& ec,
2461c1d019a6SEd Tanous                      const ::dbus::utility::MapperGetObject& subtree) {
246262598e31SEd Tanous             BMCWEB_LOG_DEBUG("respHandler1 enter");
2463aec0ec30SMyung Bae             if (ec == boost::system::errc::io_error)
2464aec0ec30SMyung Bae             {
246562598e31SEd Tanous                 BMCWEB_LOG_WARNING("Sensor not found from getSensorPaths");
2466aec0ec30SMyung Bae                 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2467aec0ec30SMyung Bae                 return;
2468aec0ec30SMyung Bae             }
2469e6bd846dSNan Zhou             if (ec)
2470e6bd846dSNan Zhou             {
2471c1d019a6SEd Tanous                 messages::internalError(asyncResp->res);
247262598e31SEd Tanous                 BMCWEB_LOG_ERROR(
247362598e31SEd Tanous                     "Sensor getSensorPaths resp_handler: Dbus error {}", ec);
2474e6bd846dSNan Zhou                 return;
2475e6bd846dSNan Zhou             }
2476c1d019a6SEd Tanous             getSensorFromDbus(asyncResp, sensorPath, subtree);
247762598e31SEd Tanous             BMCWEB_LOG_DEBUG("respHandler1 exit");
24782b73119cSGeorge Liu         });
2479e6bd846dSNan Zhou }
2480e6bd846dSNan Zhou 
2481bacb2162SNan Zhou } // namespace sensors
2482bacb2162SNan Zhou 
24837e860f15SJohn Edward Broadbent inline void requestRoutesSensorCollection(App& app)
248495a3ecadSAnthony Wilson {
24857e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
2486ed398213SEd Tanous         .privileges(redfish::privileges::getSensorCollection)
2487002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
2488de167a6fSNan Zhou             std::bind_front(sensors::handleSensorCollectionGet, std::ref(app)));
248995a3ecadSAnthony Wilson }
249095a3ecadSAnthony Wilson 
24917e860f15SJohn Edward Broadbent inline void requestRoutesSensor(App& app)
249295a3ecadSAnthony Wilson {
24937e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/")
2494ed398213SEd Tanous         .privileges(redfish::privileges::getSensor)
2495002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
2496e6bd846dSNan Zhou             std::bind_front(sensors::handleSensorGet, std::ref(app)));
249795a3ecadSAnthony Wilson }
249895a3ecadSAnthony Wilson 
249908777fb0SLewanczyk, Dawid } // namespace redfish
2500