xref: /openbmc/bmcweb/features/redfish/lib/sensors.hpp (revision 95a3ecada41219555c5efe4080d6589dc2aaa411)
108777fb0SLewanczyk, Dawid /*
208777fb0SLewanczyk, Dawid // Copyright (c) 2018 Intel Corporation
308777fb0SLewanczyk, Dawid //
408777fb0SLewanczyk, Dawid // Licensed under the Apache License, Version 2.0 (the "License");
508777fb0SLewanczyk, Dawid // you may not use this file except in compliance with the License.
608777fb0SLewanczyk, Dawid // You may obtain a copy of the License at
708777fb0SLewanczyk, Dawid //
808777fb0SLewanczyk, Dawid //      http://www.apache.org/licenses/LICENSE-2.0
908777fb0SLewanczyk, Dawid //
1008777fb0SLewanczyk, Dawid // Unless required by applicable law or agreed to in writing, software
1108777fb0SLewanczyk, Dawid // distributed under the License is distributed on an "AS IS" BASIS,
1208777fb0SLewanczyk, Dawid // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1308777fb0SLewanczyk, Dawid // See the License for the specific language governing permissions and
1408777fb0SLewanczyk, Dawid // limitations under the License.
1508777fb0SLewanczyk, Dawid */
1608777fb0SLewanczyk, Dawid #pragma once
1708777fb0SLewanczyk, Dawid 
18*95a3ecadSAnthony Wilson #include "node.hpp"
19*95a3ecadSAnthony Wilson 
2008777fb0SLewanczyk, Dawid #include <math.h>
211abe55efSEd Tanous 
2208777fb0SLewanczyk, Dawid #include <boost/algorithm/string/predicate.hpp>
2308777fb0SLewanczyk, Dawid #include <boost/algorithm/string/split.hpp>
2408777fb0SLewanczyk, Dawid #include <boost/container/flat_map.hpp>
2508777fb0SLewanczyk, Dawid #include <boost/range/algorithm/replace_copy_if.hpp>
261abe55efSEd Tanous #include <dbus_singleton.hpp>
27413961deSRichard Marian Thomaiyar #include <utils/json_utils.hpp>
28abf2add6SEd Tanous #include <variant>
2908777fb0SLewanczyk, Dawid 
301abe55efSEd Tanous namespace redfish
311abe55efSEd Tanous {
3208777fb0SLewanczyk, Dawid 
3308777fb0SLewanczyk, Dawid using GetSubTreeType = std::vector<
3408777fb0SLewanczyk, Dawid     std::pair<std::string,
3508777fb0SLewanczyk, Dawid               std::vector<std::pair<std::string, std::vector<std::string>>>>>;
3608777fb0SLewanczyk, Dawid 
37adc4f0dbSShawn McCarney using SensorVariant =
38adc4f0dbSShawn McCarney     std::variant<int64_t, double, uint32_t, bool, std::string>;
39aa2e59c1SEd Tanous 
4008777fb0SLewanczyk, Dawid using ManagedObjectsVectorType = std::vector<std::pair<
41aa2e59c1SEd Tanous     sdbusplus::message::object_path,
4208777fb0SLewanczyk, Dawid     boost::container::flat_map<
43aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>>>;
4408777fb0SLewanczyk, Dawid 
4508777fb0SLewanczyk, Dawid /**
46588c3f0dSKowalski, Kamil  * SensorsAsyncResp
4708777fb0SLewanczyk, Dawid  * Gathers data needed for response processing after async calls are done
4808777fb0SLewanczyk, Dawid  */
491abe55efSEd Tanous class SensorsAsyncResp
501abe55efSEd Tanous {
5108777fb0SLewanczyk, Dawid   public:
5255c7b7a2SEd Tanous     SensorsAsyncResp(crow::Response& response, const std::string& chassisId,
5385e1424fSEd Tanous                      const std::vector<const char*> types,
542474adfaSEd Tanous                      const std::string& subNode) :
5543b761d0SEd Tanous         res(response),
5643b761d0SEd Tanous         chassisId(chassisId), types(types), chassisSubNode(subNode)
571abe55efSEd Tanous     {
5808777fb0SLewanczyk, Dawid     }
5908777fb0SLewanczyk, Dawid 
601abe55efSEd Tanous     ~SensorsAsyncResp()
611abe55efSEd Tanous     {
621abe55efSEd Tanous         if (res.result() == boost::beast::http::status::internal_server_error)
631abe55efSEd Tanous         {
641abe55efSEd Tanous             // Reset the json object to clear out any data that made it in
651abe55efSEd Tanous             // before the error happened todo(ed) handle error condition with
661abe55efSEd Tanous             // proper code
6755c7b7a2SEd Tanous             res.jsonValue = nlohmann::json::object();
6808777fb0SLewanczyk, Dawid         }
6908777fb0SLewanczyk, Dawid         res.end();
7008777fb0SLewanczyk, Dawid     }
71588c3f0dSKowalski, Kamil 
7255c7b7a2SEd Tanous     crow::Response& res;
73588c3f0dSKowalski, Kamil     std::string chassisId{};
7408777fb0SLewanczyk, Dawid     const std::vector<const char*> types;
752474adfaSEd Tanous     std::string chassisSubNode{};
7608777fb0SLewanczyk, Dawid };
7708777fb0SLewanczyk, Dawid 
7808777fb0SLewanczyk, Dawid /**
79adc4f0dbSShawn McCarney  * D-Bus inventory item associated with one or more sensors.
80adc4f0dbSShawn McCarney  */
81adc4f0dbSShawn McCarney class InventoryItem
82adc4f0dbSShawn McCarney {
83adc4f0dbSShawn McCarney   public:
84adc4f0dbSShawn McCarney     InventoryItem(const std::string& objPath) :
85adc4f0dbSShawn McCarney         objectPath(objPath), name(), isPresent(true), isFunctional(true),
86adc4f0dbSShawn McCarney         isPowerSupply(false), manufacturer(), model(), partNumber(),
87adc4f0dbSShawn McCarney         serialNumber(), sensors()
88adc4f0dbSShawn McCarney     {
89adc4f0dbSShawn McCarney         // Set inventory item name to last node of object path
90adc4f0dbSShawn McCarney         auto pos = objectPath.rfind('/');
91adc4f0dbSShawn McCarney         if ((pos != std::string::npos) && ((pos + 1) < objectPath.size()))
92adc4f0dbSShawn McCarney         {
93adc4f0dbSShawn McCarney             name = objectPath.substr(pos + 1);
94adc4f0dbSShawn McCarney         }
95adc4f0dbSShawn McCarney     }
96adc4f0dbSShawn McCarney 
97adc4f0dbSShawn McCarney     std::string objectPath;
98adc4f0dbSShawn McCarney     std::string name;
99adc4f0dbSShawn McCarney     bool isPresent;
100adc4f0dbSShawn McCarney     bool isFunctional;
101adc4f0dbSShawn McCarney     bool isPowerSupply;
102adc4f0dbSShawn McCarney     std::string manufacturer;
103adc4f0dbSShawn McCarney     std::string model;
104adc4f0dbSShawn McCarney     std::string partNumber;
105adc4f0dbSShawn McCarney     std::string serialNumber;
106adc4f0dbSShawn McCarney     std::set<std::string> sensors;
107adc4f0dbSShawn McCarney };
108adc4f0dbSShawn McCarney 
109adc4f0dbSShawn McCarney /**
110413961deSRichard Marian Thomaiyar  * @brief Get objects with connection necessary for sensors
111588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp Pointer to object holding response data
11208777fb0SLewanczyk, Dawid  * @param sensorNames Sensors retrieved from chassis
11308777fb0SLewanczyk, Dawid  * @param callback Callback for processing gathered connections
11408777fb0SLewanczyk, Dawid  */
11508777fb0SLewanczyk, Dawid template <typename Callback>
116413961deSRichard Marian Thomaiyar void getObjectsWithConnection(
117413961deSRichard Marian Thomaiyar     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
11849c53ac9SJohnathan Mantey     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
1191abe55efSEd Tanous     Callback&& callback)
1201abe55efSEd Tanous {
121413961deSRichard Marian Thomaiyar     BMCWEB_LOG_DEBUG << "getObjectsWithConnection enter";
12203b5bae3SJames Feist     const std::string path = "/xyz/openbmc_project/sensors";
12308777fb0SLewanczyk, Dawid     const std::array<std::string, 1> interfaces = {
12408777fb0SLewanczyk, Dawid         "xyz.openbmc_project.Sensor.Value"};
12508777fb0SLewanczyk, Dawid 
12608777fb0SLewanczyk, Dawid     // Response handler for parsing objects subtree
1271abe55efSEd Tanous     auto respHandler = [callback{std::move(callback)}, SensorsAsyncResp,
1281abe55efSEd Tanous                         sensorNames](const boost::system::error_code ec,
1291abe55efSEd Tanous                                      const GetSubTreeType& subtree) {
130413961deSRichard Marian Thomaiyar         BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler enter";
1311abe55efSEd Tanous         if (ec)
1321abe55efSEd Tanous         {
1335f7d88c4SEd Tanous             messages::internalError(SensorsAsyncResp->res);
134413961deSRichard Marian Thomaiyar             BMCWEB_LOG_ERROR
135413961deSRichard Marian Thomaiyar                 << "getObjectsWithConnection resp_handler: Dbus error " << ec;
13608777fb0SLewanczyk, Dawid             return;
13708777fb0SLewanczyk, Dawid         }
13808777fb0SLewanczyk, Dawid 
13955c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
14008777fb0SLewanczyk, Dawid 
14108777fb0SLewanczyk, Dawid         // Make unique list of connections only for requested sensor types and
14208777fb0SLewanczyk, Dawid         // found in the chassis
14308777fb0SLewanczyk, Dawid         boost::container::flat_set<std::string> connections;
144413961deSRichard Marian Thomaiyar         std::set<std::pair<std::string, std::string>> objectsWithConnection;
1451abe55efSEd Tanous         // Intrinsic to avoid malloc.  Most systems will have < 8 sensor
1461abe55efSEd Tanous         // producers
14708777fb0SLewanczyk, Dawid         connections.reserve(8);
14808777fb0SLewanczyk, Dawid 
14949c53ac9SJohnathan Mantey         BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames->size();
15049c53ac9SJohnathan Mantey         for (const std::string& tsensor : *sensorNames)
1511abe55efSEd Tanous         {
15255c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor;
15308777fb0SLewanczyk, Dawid         }
15408777fb0SLewanczyk, Dawid 
15508777fb0SLewanczyk, Dawid         for (const std::pair<
15608777fb0SLewanczyk, Dawid                  std::string,
15708777fb0SLewanczyk, Dawid                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
1581abe55efSEd Tanous                  object : subtree)
1591abe55efSEd Tanous         {
16049c53ac9SJohnathan Mantey             if (sensorNames->find(object.first) != sensorNames->end())
1611abe55efSEd Tanous             {
16249c53ac9SJohnathan Mantey                 for (const std::pair<std::string, std::vector<std::string>>&
1631abe55efSEd Tanous                          objData : object.second)
1641abe55efSEd Tanous                 {
16549c53ac9SJohnathan Mantey                     BMCWEB_LOG_DEBUG << "Adding connection: " << objData.first;
16608777fb0SLewanczyk, Dawid                     connections.insert(objData.first);
167de629b6eSShawn McCarney                     objectsWithConnection.insert(
168de629b6eSShawn McCarney                         std::make_pair(object.first, objData.first));
16908777fb0SLewanczyk, Dawid                 }
17008777fb0SLewanczyk, Dawid             }
17108777fb0SLewanczyk, Dawid         }
17255c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections";
173413961deSRichard Marian Thomaiyar         callback(std::move(connections), std::move(objectsWithConnection));
174413961deSRichard Marian Thomaiyar         BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler exit";
17508777fb0SLewanczyk, Dawid     };
17608777fb0SLewanczyk, Dawid     // Make call to ObjectMapper to find all sensors objects
17755c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
17855c7b7a2SEd Tanous         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
1791abe55efSEd Tanous         "/xyz/openbmc_project/object_mapper",
1801abe55efSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 2, interfaces);
181413961deSRichard Marian Thomaiyar     BMCWEB_LOG_DEBUG << "getObjectsWithConnection exit";
182413961deSRichard Marian Thomaiyar }
183413961deSRichard Marian Thomaiyar 
184413961deSRichard Marian Thomaiyar /**
185413961deSRichard Marian Thomaiyar  * @brief Create connections necessary for sensors
186413961deSRichard Marian Thomaiyar  * @param SensorsAsyncResp Pointer to object holding response data
187413961deSRichard Marian Thomaiyar  * @param sensorNames Sensors retrieved from chassis
188413961deSRichard Marian Thomaiyar  * @param callback Callback for processing gathered connections
189413961deSRichard Marian Thomaiyar  */
190413961deSRichard Marian Thomaiyar template <typename Callback>
19149c53ac9SJohnathan Mantey void getConnections(
19249c53ac9SJohnathan Mantey     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
19349c53ac9SJohnathan Mantey     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
194413961deSRichard Marian Thomaiyar     Callback&& callback)
195413961deSRichard Marian Thomaiyar {
196413961deSRichard Marian Thomaiyar     auto objectsWithConnectionCb =
197413961deSRichard Marian Thomaiyar         [callback](const boost::container::flat_set<std::string>& connections,
198413961deSRichard Marian Thomaiyar                    const std::set<std::pair<std::string, std::string>>&
199413961deSRichard Marian Thomaiyar                        objectsWithConnection) {
200413961deSRichard Marian Thomaiyar             callback(std::move(connections));
201413961deSRichard Marian Thomaiyar         };
202413961deSRichard Marian Thomaiyar     getObjectsWithConnection(SensorsAsyncResp, sensorNames,
203413961deSRichard Marian Thomaiyar                              std::move(objectsWithConnectionCb));
20408777fb0SLewanczyk, Dawid }
20508777fb0SLewanczyk, Dawid 
20608777fb0SLewanczyk, Dawid /**
20749c53ac9SJohnathan Mantey  * @brief Shrinks the list of sensors for processing
20849c53ac9SJohnathan Mantey  * @param SensorsAysncResp  The class holding the Redfish response
20949c53ac9SJohnathan Mantey  * @param allSensors  A list of all the sensors associated to the
21049c53ac9SJohnathan Mantey  * chassis element (i.e. baseboard, front panel, etc...)
21149c53ac9SJohnathan Mantey  * @param activeSensors A list that is a reduction of the incoming
21249c53ac9SJohnathan Mantey  * allSensors list.  Eliminate Thermal sensors when a Power request is
21349c53ac9SJohnathan Mantey  * made, and eliminate Power sensors when a Thermal request is made.
21449c53ac9SJohnathan Mantey  */
21549c53ac9SJohnathan Mantey void reduceSensorList(
21649c53ac9SJohnathan Mantey     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
21749c53ac9SJohnathan Mantey     const std::vector<std::string>* allSensors,
21849c53ac9SJohnathan Mantey     std::shared_ptr<boost::container::flat_set<std::string>> activeSensors)
21949c53ac9SJohnathan Mantey {
22049c53ac9SJohnathan Mantey     if (SensorsAsyncResp == nullptr)
22149c53ac9SJohnathan Mantey     {
22249c53ac9SJohnathan Mantey         return;
22349c53ac9SJohnathan Mantey     }
22449c53ac9SJohnathan Mantey     if ((allSensors == nullptr) || (activeSensors == nullptr))
22549c53ac9SJohnathan Mantey     {
22649c53ac9SJohnathan Mantey         messages::resourceNotFound(
22749c53ac9SJohnathan Mantey             SensorsAsyncResp->res, SensorsAsyncResp->chassisSubNode,
22849c53ac9SJohnathan Mantey             SensorsAsyncResp->chassisSubNode == "Thermal" ? "Temperatures"
22949c53ac9SJohnathan Mantey                                                           : "Voltages");
23049c53ac9SJohnathan Mantey 
23149c53ac9SJohnathan Mantey         return;
23249c53ac9SJohnathan Mantey     }
23349c53ac9SJohnathan Mantey     if (allSensors->empty())
23449c53ac9SJohnathan Mantey     {
23549c53ac9SJohnathan Mantey         // Nothing to do, the activeSensors object is also empty
23649c53ac9SJohnathan Mantey         return;
23749c53ac9SJohnathan Mantey     }
23849c53ac9SJohnathan Mantey 
23949c53ac9SJohnathan Mantey     for (const char* type : SensorsAsyncResp->types)
24049c53ac9SJohnathan Mantey     {
24149c53ac9SJohnathan Mantey         for (const std::string& sensor : *allSensors)
24249c53ac9SJohnathan Mantey         {
24349c53ac9SJohnathan Mantey             if (boost::starts_with(sensor, type))
24449c53ac9SJohnathan Mantey             {
24549c53ac9SJohnathan Mantey                 activeSensors->emplace(sensor);
24649c53ac9SJohnathan Mantey             }
24749c53ac9SJohnathan Mantey         }
24849c53ac9SJohnathan Mantey     }
24949c53ac9SJohnathan Mantey }
25049c53ac9SJohnathan Mantey 
25149c53ac9SJohnathan Mantey /**
25208777fb0SLewanczyk, Dawid  * @brief Retrieves requested chassis sensors and redundancy data from DBus .
253588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
25408777fb0SLewanczyk, Dawid  * @param callback  Callback for next step in gathered sensor processing
25508777fb0SLewanczyk, Dawid  */
25608777fb0SLewanczyk, Dawid template <typename Callback>
25749c53ac9SJohnathan Mantey void getChassis(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
2581abe55efSEd Tanous                 Callback&& callback)
2591abe55efSEd Tanous {
26055c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis enter";
261adc4f0dbSShawn McCarney     const std::array<const char*, 2> interfaces = {
26249c53ac9SJohnathan Mantey         "xyz.openbmc_project.Inventory.Item.Board",
263adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Item.Chassis"};
26449c53ac9SJohnathan Mantey     auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp](
26549c53ac9SJohnathan Mantey                            const boost::system::error_code ec,
26649c53ac9SJohnathan Mantey                            const std::vector<std::string>& chassisPaths) {
26755c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassis respHandler enter";
2681abe55efSEd Tanous         if (ec)
2691abe55efSEd Tanous         {
27055c7b7a2SEd Tanous             BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec;
27149c53ac9SJohnathan Mantey             messages::internalError(sensorsAsyncResp->res);
27208777fb0SLewanczyk, Dawid             return;
27308777fb0SLewanczyk, Dawid         }
27408777fb0SLewanczyk, Dawid 
27549c53ac9SJohnathan Mantey         const std::string* chassisPath = nullptr;
27649c53ac9SJohnathan Mantey         std::string chassisName;
27749c53ac9SJohnathan Mantey         for (const std::string& chassis : chassisPaths)
2781abe55efSEd Tanous         {
27949c53ac9SJohnathan Mantey             std::size_t lastPos = chassis.rfind("/");
28049c53ac9SJohnathan Mantey             if (lastPos == std::string::npos)
2811abe55efSEd Tanous             {
28249c53ac9SJohnathan Mantey                 BMCWEB_LOG_ERROR << "Failed to find '/' in " << chassis;
283daf36e2eSEd Tanous                 continue;
284daf36e2eSEd Tanous             }
28549c53ac9SJohnathan Mantey             chassisName = chassis.substr(lastPos + 1);
28649c53ac9SJohnathan Mantey             if (chassisName == sensorsAsyncResp->chassisId)
2871abe55efSEd Tanous             {
28849c53ac9SJohnathan Mantey                 chassisPath = &chassis;
28949c53ac9SJohnathan Mantey                 break;
290daf36e2eSEd Tanous             }
29149c53ac9SJohnathan Mantey         }
29249c53ac9SJohnathan Mantey         if (chassisPath == nullptr)
2931abe55efSEd Tanous         {
29449c53ac9SJohnathan Mantey             messages::resourceNotFound(sensorsAsyncResp->res, "Chassis",
29549c53ac9SJohnathan Mantey                                        sensorsAsyncResp->chassisId);
29649c53ac9SJohnathan Mantey             return;
2971abe55efSEd Tanous         }
29808777fb0SLewanczyk, Dawid 
29949c53ac9SJohnathan Mantey         const std::string& chassisSubNode = sensorsAsyncResp->chassisSubNode;
30049c53ac9SJohnathan Mantey         if (chassisSubNode == "Power")
30149c53ac9SJohnathan Mantey         {
30249c53ac9SJohnathan Mantey             sensorsAsyncResp->res.jsonValue["@odata.type"] =
30349c53ac9SJohnathan Mantey                 "#Power.v1_5_2.Power";
30449c53ac9SJohnathan Mantey         }
30549c53ac9SJohnathan Mantey         else if (chassisSubNode == "Thermal")
30649c53ac9SJohnathan Mantey         {
30749c53ac9SJohnathan Mantey             sensorsAsyncResp->res.jsonValue["@odata.type"] =
30849c53ac9SJohnathan Mantey                 "#Thermal.v1_4_0.Thermal";
3094f9a2130SJennifer Lee             sensorsAsyncResp->res.jsonValue["Fans"] = nlohmann::json::array();
3104f9a2130SJennifer Lee             sensorsAsyncResp->res.jsonValue["Temperatures"] =
3114f9a2130SJennifer Lee                 nlohmann::json::array();
31249c53ac9SJohnathan Mantey         }
313*95a3ecadSAnthony Wilson         else if (chassisSubNode == "Sensors")
314*95a3ecadSAnthony Wilson         {
315*95a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["@odata.type"] =
316*95a3ecadSAnthony Wilson                 "#SensorCollection.SensorCollection";
317*95a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["@odata.context"] =
318*95a3ecadSAnthony Wilson                 "/redfish/v1/$metadata#SensorCollection.SensorCollection";
319*95a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["Description"] =
320*95a3ecadSAnthony Wilson                 "Collection of Sensors for this Chassis";
321*95a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["Members"] =
322*95a3ecadSAnthony Wilson                 nlohmann::json::array();
323*95a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["Members@odata.count"] = 0;
324*95a3ecadSAnthony Wilson         }
325*95a3ecadSAnthony Wilson 
326*95a3ecadSAnthony Wilson         if (chassisSubNode != "Sensors")
327*95a3ecadSAnthony Wilson         {
328*95a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["Id"] = chassisSubNode;
329*95a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["@odata.context"] =
330*95a3ecadSAnthony Wilson                 "/redfish/v1/$metadata#" + chassisSubNode + "." +
331*95a3ecadSAnthony Wilson                 chassisSubNode;
332*95a3ecadSAnthony Wilson         }
333*95a3ecadSAnthony Wilson 
33449c53ac9SJohnathan Mantey         sensorsAsyncResp->res.jsonValue["@odata.id"] =
33549c53ac9SJohnathan Mantey             "/redfish/v1/Chassis/" + sensorsAsyncResp->chassisId + "/" +
33649c53ac9SJohnathan Mantey             chassisSubNode;
33749c53ac9SJohnathan Mantey         sensorsAsyncResp->res.jsonValue["Name"] = chassisSubNode;
33849c53ac9SJohnathan Mantey 
3398fb49dd6SShawn McCarney         // Get the list of all sensors for this Chassis element
3408fb49dd6SShawn McCarney         std::string sensorPath = *chassisPath + "/all_sensors";
34155c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
34249c53ac9SJohnathan Mantey             [sensorsAsyncResp, callback{std::move(callback)}](
34349c53ac9SJohnathan Mantey                 const boost::system::error_code ec,
34449c53ac9SJohnathan Mantey                 const std::variant<std::vector<std::string>>&
34549c53ac9SJohnathan Mantey                     variantEndpoints) {
34649c53ac9SJohnathan Mantey                 if (ec)
34749c53ac9SJohnathan Mantey                 {
34849c53ac9SJohnathan Mantey                     if (ec.value() != EBADR)
34949c53ac9SJohnathan Mantey                     {
35049c53ac9SJohnathan Mantey                         messages::internalError(sensorsAsyncResp->res);
35149c53ac9SJohnathan Mantey                         return;
35249c53ac9SJohnathan Mantey                     }
35349c53ac9SJohnathan Mantey                 }
35449c53ac9SJohnathan Mantey                 const std::vector<std::string>* nodeSensorList =
35549c53ac9SJohnathan Mantey                     std::get_if<std::vector<std::string>>(&(variantEndpoints));
35649c53ac9SJohnathan Mantey                 if (nodeSensorList == nullptr)
35749c53ac9SJohnathan Mantey                 {
35849c53ac9SJohnathan Mantey                     messages::resourceNotFound(
35949c53ac9SJohnathan Mantey                         sensorsAsyncResp->res, sensorsAsyncResp->chassisSubNode,
36049c53ac9SJohnathan Mantey                         sensorsAsyncResp->chassisSubNode == "Thermal"
36149c53ac9SJohnathan Mantey                             ? "Temperatures"
362*95a3ecadSAnthony Wilson                             : sensorsAsyncResp->chassisSubNode == "Power"
363*95a3ecadSAnthony Wilson                                   ? "Voltages"
364*95a3ecadSAnthony Wilson                                   : "Sensors");
36549c53ac9SJohnathan Mantey                     return;
36649c53ac9SJohnathan Mantey                 }
36749c53ac9SJohnathan Mantey                 const std::shared_ptr<boost::container::flat_set<std::string>>
36849c53ac9SJohnathan Mantey                     culledSensorList = std::make_shared<
36949c53ac9SJohnathan Mantey                         boost::container::flat_set<std::string>>();
37049c53ac9SJohnathan Mantey                 reduceSensorList(sensorsAsyncResp, nodeSensorList,
37149c53ac9SJohnathan Mantey                                  culledSensorList);
37249c53ac9SJohnathan Mantey                 callback(culledSensorList);
37349c53ac9SJohnathan Mantey             },
37449c53ac9SJohnathan Mantey             "xyz.openbmc_project.ObjectMapper", sensorPath,
37549c53ac9SJohnathan Mantey             "org.freedesktop.DBus.Properties", "Get",
37649c53ac9SJohnathan Mantey             "xyz.openbmc_project.Association", "endpoints");
37749c53ac9SJohnathan Mantey     };
37849c53ac9SJohnathan Mantey 
37949c53ac9SJohnathan Mantey     // Get the Chassis Collection
38049c53ac9SJohnathan Mantey     crow::connections::systemBus->async_method_call(
38149c53ac9SJohnathan Mantey         respHandler, "xyz.openbmc_project.ObjectMapper",
38249c53ac9SJohnathan Mantey         "/xyz/openbmc_project/object_mapper",
38349c53ac9SJohnathan Mantey         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
38449c53ac9SJohnathan Mantey         "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
38555c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis exit";
38608777fb0SLewanczyk, Dawid }
38708777fb0SLewanczyk, Dawid 
38808777fb0SLewanczyk, Dawid /**
389de629b6eSShawn McCarney  * @brief Finds all DBus object paths that implement ObjectManager.
390de629b6eSShawn McCarney  *
391de629b6eSShawn McCarney  * Creates a mapping from the associated connection name to the object path.
392de629b6eSShawn McCarney  *
393de629b6eSShawn McCarney  * Finds the object paths asynchronously.  Invokes callback when information has
394de629b6eSShawn McCarney  * been obtained.
395de629b6eSShawn McCarney  *
396de629b6eSShawn McCarney  * The callback must have the following signature:
397de629b6eSShawn McCarney  *   @code
3988fb49dd6SShawn McCarney  *   callback(std::shared_ptr<boost::container::flat_map<std::string,
3998fb49dd6SShawn McCarney  *                std::string>> objectMgrPaths)
400de629b6eSShawn McCarney  *   @endcode
401de629b6eSShawn McCarney  *
40249c53ac9SJohnathan Mantey  * @param sensorsAsyncResp Pointer to object holding response data.
403de629b6eSShawn McCarney  * @param callback Callback to invoke when object paths obtained.
404de629b6eSShawn McCarney  */
405de629b6eSShawn McCarney template <typename Callback>
406de629b6eSShawn McCarney void getObjectManagerPaths(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
407de629b6eSShawn McCarney                            Callback&& callback)
408de629b6eSShawn McCarney {
409de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getObjectManagerPaths enter";
410de629b6eSShawn McCarney     const std::array<std::string, 1> interfaces = {
411de629b6eSShawn McCarney         "org.freedesktop.DBus.ObjectManager"};
412de629b6eSShawn McCarney 
413de629b6eSShawn McCarney     // Response handler for GetSubTree DBus method
414de629b6eSShawn McCarney     auto respHandler = [callback{std::move(callback)},
415de629b6eSShawn McCarney                         SensorsAsyncResp](const boost::system::error_code ec,
416de629b6eSShawn McCarney                                           const GetSubTreeType& subtree) {
417de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler enter";
418de629b6eSShawn McCarney         if (ec)
419de629b6eSShawn McCarney         {
420de629b6eSShawn McCarney             messages::internalError(SensorsAsyncResp->res);
421de629b6eSShawn McCarney             BMCWEB_LOG_ERROR << "getObjectManagerPaths respHandler: DBus error "
422de629b6eSShawn McCarney                              << ec;
423de629b6eSShawn McCarney             return;
424de629b6eSShawn McCarney         }
425de629b6eSShawn McCarney 
426de629b6eSShawn McCarney         // Loop over returned object paths
4278fb49dd6SShawn McCarney         std::shared_ptr<boost::container::flat_map<std::string, std::string>>
4288fb49dd6SShawn McCarney             objectMgrPaths = std::make_shared<
4298fb49dd6SShawn McCarney                 boost::container::flat_map<std::string, std::string>>();
430de629b6eSShawn McCarney         for (const std::pair<
431de629b6eSShawn McCarney                  std::string,
432de629b6eSShawn McCarney                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
433de629b6eSShawn McCarney                  object : subtree)
434de629b6eSShawn McCarney         {
435de629b6eSShawn McCarney             // Loop over connections for current object path
436de629b6eSShawn McCarney             const std::string& objectPath = object.first;
437de629b6eSShawn McCarney             for (const std::pair<std::string, std::vector<std::string>>&
438de629b6eSShawn McCarney                      objData : object.second)
439de629b6eSShawn McCarney             {
440de629b6eSShawn McCarney                 // Add mapping from connection to object path
441de629b6eSShawn McCarney                 const std::string& connection = objData.first;
4428fb49dd6SShawn McCarney                 (*objectMgrPaths)[connection] = objectPath;
443de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "Added mapping " << connection << " -> "
444de629b6eSShawn McCarney                                  << objectPath;
445de629b6eSShawn McCarney             }
446de629b6eSShawn McCarney         }
4478fb49dd6SShawn McCarney         callback(objectMgrPaths);
448de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler exit";
449de629b6eSShawn McCarney     };
450de629b6eSShawn McCarney 
451de629b6eSShawn McCarney     // Query mapper for all DBus object paths that implement ObjectManager
452de629b6eSShawn McCarney     crow::connections::systemBus->async_method_call(
453de629b6eSShawn McCarney         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
454de629b6eSShawn McCarney         "/xyz/openbmc_project/object_mapper",
455de629b6eSShawn McCarney         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
456de629b6eSShawn McCarney         interfaces);
457de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getObjectManagerPaths exit";
458de629b6eSShawn McCarney }
459de629b6eSShawn McCarney 
460de629b6eSShawn McCarney /**
461adc4f0dbSShawn McCarney  * @brief Returns the Redfish State value for the specified inventory item.
462adc4f0dbSShawn McCarney  * @param inventoryItem D-Bus inventory item associated with a sensor.
463adc4f0dbSShawn McCarney  * @return State value for inventory item.
46434dd179eSJames Feist  */
465adc4f0dbSShawn McCarney static std::string getState(const InventoryItem* inventoryItem)
466adc4f0dbSShawn McCarney {
467adc4f0dbSShawn McCarney     if ((inventoryItem != nullptr) && !(inventoryItem->isPresent))
468adc4f0dbSShawn McCarney     {
469adc4f0dbSShawn McCarney         return "Absent";
470adc4f0dbSShawn McCarney     }
47134dd179eSJames Feist 
472adc4f0dbSShawn McCarney     return "Enabled";
473adc4f0dbSShawn McCarney }
474adc4f0dbSShawn McCarney 
475adc4f0dbSShawn McCarney /**
476adc4f0dbSShawn McCarney  * @brief Returns the Redfish Health value for the specified sensor.
477adc4f0dbSShawn McCarney  * @param sensorJson Sensor JSON object.
478adc4f0dbSShawn McCarney  * @param interfacesDict Map of all sensor interfaces.
479adc4f0dbSShawn McCarney  * @param inventoryItem D-Bus inventory item associated with the sensor.  Will
480adc4f0dbSShawn McCarney  * be nullptr if no associated inventory item was found.
481adc4f0dbSShawn McCarney  * @return Health value for sensor.
482adc4f0dbSShawn McCarney  */
48334dd179eSJames Feist static std::string getHealth(
484adc4f0dbSShawn McCarney     nlohmann::json& sensorJson,
48534dd179eSJames Feist     const boost::container::flat_map<
48634dd179eSJames Feist         std::string, boost::container::flat_map<std::string, SensorVariant>>&
487adc4f0dbSShawn McCarney         interfacesDict,
488adc4f0dbSShawn McCarney     const InventoryItem* inventoryItem)
48934dd179eSJames Feist {
490adc4f0dbSShawn McCarney     // Get current health value (if any) in the sensor JSON object.  Some JSON
491adc4f0dbSShawn McCarney     // objects contain multiple sensors (such as PowerSupplies).  We want to set
492adc4f0dbSShawn McCarney     // the overall health to be the most severe of any of the sensors.
493adc4f0dbSShawn McCarney     std::string currentHealth;
494adc4f0dbSShawn McCarney     auto statusIt = sensorJson.find("Status");
495adc4f0dbSShawn McCarney     if (statusIt != sensorJson.end())
496adc4f0dbSShawn McCarney     {
497adc4f0dbSShawn McCarney         auto healthIt = statusIt->find("Health");
498adc4f0dbSShawn McCarney         if (healthIt != statusIt->end())
499adc4f0dbSShawn McCarney         {
500adc4f0dbSShawn McCarney             std::string* health = healthIt->get_ptr<std::string*>();
501adc4f0dbSShawn McCarney             if (health != nullptr)
502adc4f0dbSShawn McCarney             {
503adc4f0dbSShawn McCarney                 currentHealth = *health;
504adc4f0dbSShawn McCarney             }
505adc4f0dbSShawn McCarney         }
506adc4f0dbSShawn McCarney     }
507adc4f0dbSShawn McCarney 
508adc4f0dbSShawn McCarney     // If current health in JSON object is already Critical, return that.  This
509adc4f0dbSShawn McCarney     // should override the sensor health, which might be less severe.
510adc4f0dbSShawn McCarney     if (currentHealth == "Critical")
511adc4f0dbSShawn McCarney     {
512adc4f0dbSShawn McCarney         return "Critical";
513adc4f0dbSShawn McCarney     }
514adc4f0dbSShawn McCarney 
515adc4f0dbSShawn McCarney     // Check if sensor has critical threshold alarm
51634dd179eSJames Feist     auto criticalThresholdIt =
51734dd179eSJames Feist         interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Critical");
51834dd179eSJames Feist     if (criticalThresholdIt != interfacesDict.end())
51934dd179eSJames Feist     {
52034dd179eSJames Feist         auto thresholdHighIt =
52134dd179eSJames Feist             criticalThresholdIt->second.find("CriticalAlarmHigh");
52234dd179eSJames Feist         auto thresholdLowIt =
52334dd179eSJames Feist             criticalThresholdIt->second.find("CriticalAlarmLow");
52434dd179eSJames Feist         if (thresholdHighIt != criticalThresholdIt->second.end())
52534dd179eSJames Feist         {
52634dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdHighIt->second);
52734dd179eSJames Feist             if (asserted == nullptr)
52834dd179eSJames Feist             {
52934dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
53034dd179eSJames Feist             }
53134dd179eSJames Feist             else if (*asserted)
53234dd179eSJames Feist             {
53334dd179eSJames Feist                 return "Critical";
53434dd179eSJames Feist             }
53534dd179eSJames Feist         }
53634dd179eSJames Feist         if (thresholdLowIt != criticalThresholdIt->second.end())
53734dd179eSJames Feist         {
53834dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdLowIt->second);
53934dd179eSJames Feist             if (asserted == nullptr)
54034dd179eSJames Feist             {
54134dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
54234dd179eSJames Feist             }
54334dd179eSJames Feist             else if (*asserted)
54434dd179eSJames Feist             {
54534dd179eSJames Feist                 return "Critical";
54634dd179eSJames Feist             }
54734dd179eSJames Feist         }
54834dd179eSJames Feist     }
54934dd179eSJames Feist 
550adc4f0dbSShawn McCarney     // Check if associated inventory item is not functional
551adc4f0dbSShawn McCarney     if ((inventoryItem != nullptr) && !(inventoryItem->isFunctional))
552adc4f0dbSShawn McCarney     {
553adc4f0dbSShawn McCarney         return "Critical";
554adc4f0dbSShawn McCarney     }
555adc4f0dbSShawn McCarney 
556adc4f0dbSShawn McCarney     // If current health in JSON object is already Warning, return that.  This
557adc4f0dbSShawn McCarney     // should override the sensor status, which might be less severe.
558adc4f0dbSShawn McCarney     if (currentHealth == "Warning")
559adc4f0dbSShawn McCarney     {
560adc4f0dbSShawn McCarney         return "Warning";
561adc4f0dbSShawn McCarney     }
562adc4f0dbSShawn McCarney 
563adc4f0dbSShawn McCarney     // Check if sensor has warning threshold alarm
56434dd179eSJames Feist     auto warningThresholdIt =
56534dd179eSJames Feist         interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Warning");
56634dd179eSJames Feist     if (warningThresholdIt != interfacesDict.end())
56734dd179eSJames Feist     {
56834dd179eSJames Feist         auto thresholdHighIt =
56934dd179eSJames Feist             warningThresholdIt->second.find("WarningAlarmHigh");
57034dd179eSJames Feist         auto thresholdLowIt =
57134dd179eSJames Feist             warningThresholdIt->second.find("WarningAlarmLow");
57234dd179eSJames Feist         if (thresholdHighIt != warningThresholdIt->second.end())
57334dd179eSJames Feist         {
57434dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdHighIt->second);
57534dd179eSJames Feist             if (asserted == nullptr)
57634dd179eSJames Feist             {
57734dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
57834dd179eSJames Feist             }
57934dd179eSJames Feist             else if (*asserted)
58034dd179eSJames Feist             {
58134dd179eSJames Feist                 return "Warning";
58234dd179eSJames Feist             }
58334dd179eSJames Feist         }
58434dd179eSJames Feist         if (thresholdLowIt != warningThresholdIt->second.end())
58534dd179eSJames Feist         {
58634dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdLowIt->second);
58734dd179eSJames Feist             if (asserted == nullptr)
58834dd179eSJames Feist             {
58934dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
59034dd179eSJames Feist             }
59134dd179eSJames Feist             else if (*asserted)
59234dd179eSJames Feist             {
59334dd179eSJames Feist                 return "Warning";
59434dd179eSJames Feist             }
59534dd179eSJames Feist         }
59634dd179eSJames Feist     }
597adc4f0dbSShawn McCarney 
59834dd179eSJames Feist     return "OK";
59934dd179eSJames Feist }
60034dd179eSJames Feist 
60134dd179eSJames Feist /**
60208777fb0SLewanczyk, Dawid  * @brief Builds a json sensor representation of a sensor.
60308777fb0SLewanczyk, Dawid  * @param sensorName  The name of the sensor to be built
604274fad5aSGunnar Mills  * @param sensorType  The type (temperature, fan_tach, etc) of the sensor to
60508777fb0SLewanczyk, Dawid  * build
606*95a3ecadSAnthony Wilson  * @param sensorSchema  The schema (Power, Thermal, etc) being associated with
607*95a3ecadSAnthony Wilson  * the sensor to build
60808777fb0SLewanczyk, Dawid  * @param interfacesDict  A dictionary of the interfaces and properties of said
60908777fb0SLewanczyk, Dawid  * interfaces to be built from
61008777fb0SLewanczyk, Dawid  * @param sensor_json  The json object to fill
611adc4f0dbSShawn McCarney  * @param inventoryItem D-Bus inventory item associated with the sensor.  Will
612adc4f0dbSShawn McCarney  * be nullptr if no associated inventory item was found.
61308777fb0SLewanczyk, Dawid  */
61408777fb0SLewanczyk, Dawid void objectInterfacesToJson(
61508777fb0SLewanczyk, Dawid     const std::string& sensorName, const std::string& sensorType,
616*95a3ecadSAnthony Wilson     const std::string& sensorSchema,
61708777fb0SLewanczyk, Dawid     const boost::container::flat_map<
618aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>&
61908777fb0SLewanczyk, Dawid         interfacesDict,
620adc4f0dbSShawn McCarney     nlohmann::json& sensor_json, InventoryItem* inventoryItem)
6211abe55efSEd Tanous {
62208777fb0SLewanczyk, Dawid     // We need a value interface before we can do anything with it
62355c7b7a2SEd Tanous     auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
6241abe55efSEd Tanous     if (valueIt == interfacesDict.end())
6251abe55efSEd Tanous     {
62655c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface";
62708777fb0SLewanczyk, Dawid         return;
62808777fb0SLewanczyk, Dawid     }
62908777fb0SLewanczyk, Dawid 
63008777fb0SLewanczyk, Dawid     // Assume values exist as is (10^0 == 1) if no scale exists
63108777fb0SLewanczyk, Dawid     int64_t scaleMultiplier = 0;
63208777fb0SLewanczyk, Dawid 
63355c7b7a2SEd Tanous     auto scaleIt = valueIt->second.find("Scale");
63408777fb0SLewanczyk, Dawid     // If a scale exists, pull value as int64, and use the scaling.
6351abe55efSEd Tanous     if (scaleIt != valueIt->second.end())
6361abe55efSEd Tanous     {
637abf2add6SEd Tanous         const int64_t* int64Value = std::get_if<int64_t>(&scaleIt->second);
6381abe55efSEd Tanous         if (int64Value != nullptr)
6391abe55efSEd Tanous         {
64008777fb0SLewanczyk, Dawid             scaleMultiplier = *int64Value;
64108777fb0SLewanczyk, Dawid         }
64208777fb0SLewanczyk, Dawid     }
64308777fb0SLewanczyk, Dawid 
644*95a3ecadSAnthony Wilson     if (sensorSchema == "Sensors")
645adc4f0dbSShawn McCarney     {
646*95a3ecadSAnthony Wilson         // For sensors in SensorCollection we set Id instead of MemberId,
647*95a3ecadSAnthony Wilson         // including power sensors.
648*95a3ecadSAnthony Wilson         sensor_json["Id"] = sensorName;
649*95a3ecadSAnthony Wilson         sensor_json["Name"] = boost::replace_all_copy(sensorName, "_", " ");
650*95a3ecadSAnthony Wilson     }
651*95a3ecadSAnthony Wilson     else if (sensorType != "power")
652*95a3ecadSAnthony Wilson     {
653*95a3ecadSAnthony Wilson         // Set MemberId and Name for non-power sensors.  For PowerSupplies and
654*95a3ecadSAnthony Wilson         // PowerControl, those properties have more general values because
655*95a3ecadSAnthony Wilson         // multiple sensors can be stored in the same JSON object.
65608777fb0SLewanczyk, Dawid         sensor_json["MemberId"] = sensorName;
657e742b6ccSEd Tanous         sensor_json["Name"] = boost::replace_all_copy(sensorName, "_", " ");
658adc4f0dbSShawn McCarney     }
659e742b6ccSEd Tanous 
660adc4f0dbSShawn McCarney     sensor_json["Status"]["State"] = getState(inventoryItem);
661adc4f0dbSShawn McCarney     sensor_json["Status"]["Health"] =
662adc4f0dbSShawn McCarney         getHealth(sensor_json, interfacesDict, inventoryItem);
66308777fb0SLewanczyk, Dawid 
66408777fb0SLewanczyk, Dawid     // Parameter to set to override the type we get from dbus, and force it to
66508777fb0SLewanczyk, Dawid     // int, regardless of what is available.  This is used for schemas like fan,
66608777fb0SLewanczyk, Dawid     // that require integers, not floats.
66708777fb0SLewanczyk, Dawid     bool forceToInt = false;
66808777fb0SLewanczyk, Dawid 
66908777fb0SLewanczyk, Dawid     const char* unit = "Reading";
670*95a3ecadSAnthony Wilson     if (sensorSchema == "Sensors")
671*95a3ecadSAnthony Wilson     {
672*95a3ecadSAnthony Wilson         sensor_json["@odata.type"] = "#Sensor.v1_0_0.Sensor";
673*95a3ecadSAnthony Wilson         sensor_json["@odata.context"] = "/redfish/v1/$metadata#Sensor.Sensor";
674*95a3ecadSAnthony Wilson         if (sensorType == "power")
675*95a3ecadSAnthony Wilson         {
676*95a3ecadSAnthony Wilson             sensor_json["ReadingUnits"] = "Watts";
677*95a3ecadSAnthony Wilson         }
678*95a3ecadSAnthony Wilson         else if (sensorType == "current")
679*95a3ecadSAnthony Wilson         {
680*95a3ecadSAnthony Wilson             sensor_json["ReadingUnits"] = "Amperes";
681*95a3ecadSAnthony Wilson         }
682*95a3ecadSAnthony Wilson     }
683*95a3ecadSAnthony Wilson     else if (sensorType == "temperature")
6841abe55efSEd Tanous     {
68508777fb0SLewanczyk, Dawid         unit = "ReadingCelsius";
6867885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature";
68708777fb0SLewanczyk, Dawid         // TODO(ed) Documentation says that path should be type fan_tach,
68808777fb0SLewanczyk, Dawid         // implementation seems to implement fan
6891abe55efSEd Tanous     }
6901abe55efSEd Tanous     else if (sensorType == "fan" || sensorType == "fan_tach")
6911abe55efSEd Tanous     {
69208777fb0SLewanczyk, Dawid         unit = "Reading";
69308777fb0SLewanczyk, Dawid         sensor_json["ReadingUnits"] = "RPM";
6947885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
69508777fb0SLewanczyk, Dawid         forceToInt = true;
6961abe55efSEd Tanous     }
6976f6d0d32SEd Tanous     else if (sensorType == "fan_pwm")
6986f6d0d32SEd Tanous     {
6996f6d0d32SEd Tanous         unit = "Reading";
7006f6d0d32SEd Tanous         sensor_json["ReadingUnits"] = "Percent";
7016f6d0d32SEd Tanous         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
7026f6d0d32SEd Tanous         forceToInt = true;
7036f6d0d32SEd Tanous     }
7041abe55efSEd Tanous     else if (sensorType == "voltage")
7051abe55efSEd Tanous     {
70608777fb0SLewanczyk, Dawid         unit = "ReadingVolts";
7077885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage";
7081abe55efSEd Tanous     }
7092474adfaSEd Tanous     else if (sensorType == "power")
7102474adfaSEd Tanous     {
71149c53ac9SJohnathan Mantey         std::string sensorNameLower =
71249c53ac9SJohnathan Mantey             boost::algorithm::to_lower_copy(sensorName);
71349c53ac9SJohnathan Mantey 
714028f7ebcSEddie James         if (!sensorName.compare("total_power"))
715028f7ebcSEddie James         {
7167ab06f49SGunnar Mills             sensor_json["@odata.type"] = "#Power.v1_0_0.PowerControl";
7177ab06f49SGunnar Mills             // Put multiple "sensors" into a single PowerControl, so have
7187ab06f49SGunnar Mills             // generic names for MemberId and Name. Follows Redfish mockup.
7197ab06f49SGunnar Mills             sensor_json["MemberId"] = "0";
7207ab06f49SGunnar Mills             sensor_json["Name"] = "Chassis Power Control";
721028f7ebcSEddie James             unit = "PowerConsumedWatts";
722028f7ebcSEddie James         }
723028f7ebcSEddie James         else if (sensorNameLower.find("input") != std::string::npos)
72449c53ac9SJohnathan Mantey         {
72549c53ac9SJohnathan Mantey             unit = "PowerInputWatts";
72649c53ac9SJohnathan Mantey         }
72749c53ac9SJohnathan Mantey         else
72849c53ac9SJohnathan Mantey         {
72949c53ac9SJohnathan Mantey             unit = "PowerOutputWatts";
73049c53ac9SJohnathan Mantey         }
7312474adfaSEd Tanous     }
7321abe55efSEd Tanous     else
7331abe55efSEd Tanous     {
73455c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
73508777fb0SLewanczyk, Dawid         return;
73608777fb0SLewanczyk, Dawid     }
73708777fb0SLewanczyk, Dawid     // Map of dbus interface name, dbus property name and redfish property_name
73808777fb0SLewanczyk, Dawid     std::vector<std::tuple<const char*, const char*, const char*>> properties;
73908777fb0SLewanczyk, Dawid     properties.reserve(7);
74008777fb0SLewanczyk, Dawid 
74108777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
742de629b6eSShawn McCarney 
743*95a3ecadSAnthony Wilson     if (sensorType != "power" && sensorSchema != "Sensors")
744de629b6eSShawn McCarney     {
74508777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
74608777fb0SLewanczyk, Dawid                                 "WarningHigh", "UpperThresholdNonCritical");
74708777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
74808777fb0SLewanczyk, Dawid                                 "WarningLow", "LowerThresholdNonCritical");
74908777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
75008777fb0SLewanczyk, Dawid                                 "CriticalHigh", "UpperThresholdCritical");
75108777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
75208777fb0SLewanczyk, Dawid                                 "CriticalLow", "LowerThresholdCritical");
753de629b6eSShawn McCarney     }
75408777fb0SLewanczyk, Dawid 
7552474adfaSEd Tanous     // TODO Need to get UpperThresholdFatal and LowerThresholdFatal
7562474adfaSEd Tanous 
757*95a3ecadSAnthony Wilson     if (sensorSchema == "Sensors")
758*95a3ecadSAnthony Wilson     {
759*95a3ecadSAnthony Wilson         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
760*95a3ecadSAnthony Wilson                                 "ReadingRangeMin");
761*95a3ecadSAnthony Wilson         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
762*95a3ecadSAnthony Wilson                                 "ReadingRangeMax");
763*95a3ecadSAnthony Wilson     }
764*95a3ecadSAnthony Wilson     else if (sensorType == "temperature")
7651abe55efSEd Tanous     {
76608777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
76708777fb0SLewanczyk, Dawid                                 "MinReadingRangeTemp");
76808777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
76908777fb0SLewanczyk, Dawid                                 "MaxReadingRangeTemp");
7701abe55efSEd Tanous     }
771adc4f0dbSShawn McCarney     else if (sensorType != "power")
7721abe55efSEd Tanous     {
77308777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
77408777fb0SLewanczyk, Dawid                                 "MinReadingRange");
77508777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
77608777fb0SLewanczyk, Dawid                                 "MaxReadingRange");
77708777fb0SLewanczyk, Dawid     }
77808777fb0SLewanczyk, Dawid 
77908777fb0SLewanczyk, Dawid     for (const std::tuple<const char*, const char*, const char*>& p :
7801abe55efSEd Tanous          properties)
7811abe55efSEd Tanous     {
78208777fb0SLewanczyk, Dawid         auto interfaceProperties = interfacesDict.find(std::get<0>(p));
7831abe55efSEd Tanous         if (interfaceProperties != interfacesDict.end())
7841abe55efSEd Tanous         {
785b01bf299SEd Tanous             auto valueIt = interfaceProperties->second.find(std::get<1>(p));
786b01bf299SEd Tanous             if (valueIt != interfaceProperties->second.end())
7871abe55efSEd Tanous             {
788b01bf299SEd Tanous                 const SensorVariant& valueVariant = valueIt->second;
789b01bf299SEd Tanous                 nlohmann::json& valueIt = sensor_json[std::get<2>(p)];
79008777fb0SLewanczyk, Dawid                 // Attempt to pull the int64 directly
791abf2add6SEd Tanous                 const int64_t* int64Value = std::get_if<int64_t>(&valueVariant);
79208777fb0SLewanczyk, Dawid 
793abf2add6SEd Tanous                 const double* doubleValue = std::get_if<double>(&valueVariant);
794028f7ebcSEddie James                 const uint32_t* uValue = std::get_if<uint32_t>(&valueVariant);
7956f6d0d32SEd Tanous                 double temp = 0.0;
7966f6d0d32SEd Tanous                 if (int64Value != nullptr)
7971abe55efSEd Tanous                 {
7986f6d0d32SEd Tanous                     temp = *int64Value;
7996f6d0d32SEd Tanous                 }
8006f6d0d32SEd Tanous                 else if (doubleValue != nullptr)
8011abe55efSEd Tanous                 {
8026f6d0d32SEd Tanous                     temp = *doubleValue;
8031abe55efSEd Tanous                 }
804028f7ebcSEddie James                 else if (uValue != nullptr)
805028f7ebcSEddie James                 {
806028f7ebcSEddie James                     temp = *uValue;
807028f7ebcSEddie James                 }
8081abe55efSEd Tanous                 else
8091abe55efSEd Tanous                 {
8106f6d0d32SEd Tanous                     BMCWEB_LOG_ERROR
8116f6d0d32SEd Tanous                         << "Got value interface that wasn't int or double";
8126f6d0d32SEd Tanous                     continue;
81308777fb0SLewanczyk, Dawid                 }
8146f6d0d32SEd Tanous                 temp = temp * std::pow(10, scaleMultiplier);
8156f6d0d32SEd Tanous                 if (forceToInt)
8166f6d0d32SEd Tanous                 {
817b01bf299SEd Tanous                     valueIt = static_cast<int64_t>(temp);
8186f6d0d32SEd Tanous                 }
8196f6d0d32SEd Tanous                 else
8206f6d0d32SEd Tanous                 {
821b01bf299SEd Tanous                     valueIt = temp;
82208777fb0SLewanczyk, Dawid                 }
82308777fb0SLewanczyk, Dawid             }
82408777fb0SLewanczyk, Dawid         }
82508777fb0SLewanczyk, Dawid     }
82655c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
82708777fb0SLewanczyk, Dawid }
82808777fb0SLewanczyk, Dawid 
8298bd25ccdSJames Feist static void
8308bd25ccdSJames Feist     populateFanRedundancy(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp)
8318bd25ccdSJames Feist {
8328bd25ccdSJames Feist     crow::connections::systemBus->async_method_call(
8338bd25ccdSJames Feist         [sensorsAsyncResp](const boost::system::error_code ec,
8348bd25ccdSJames Feist                            const GetSubTreeType& resp) {
8358bd25ccdSJames Feist             if (ec)
8368bd25ccdSJames Feist             {
8378bd25ccdSJames Feist                 return; // don't have to have this interface
8388bd25ccdSJames Feist             }
839e278c18fSEd Tanous             for (const std::pair<std::string,
840e278c18fSEd Tanous                                  std::vector<std::pair<
841e278c18fSEd Tanous                                      std::string, std::vector<std::string>>>>&
842e278c18fSEd Tanous                      pathPair : resp)
8438bd25ccdSJames Feist             {
844e278c18fSEd Tanous                 const std::string& path = pathPair.first;
845e278c18fSEd Tanous                 const std::vector<
846e278c18fSEd Tanous                     std::pair<std::string, std::vector<std::string>>>& objDict =
847e278c18fSEd Tanous                     pathPair.second;
8488bd25ccdSJames Feist                 if (objDict.empty())
8498bd25ccdSJames Feist                 {
8508bd25ccdSJames Feist                     continue; // this should be impossible
8518bd25ccdSJames Feist                 }
8528bd25ccdSJames Feist 
8538bd25ccdSJames Feist                 const std::string& owner = objDict.begin()->first;
8548bd25ccdSJames Feist                 crow::connections::systemBus->async_method_call(
8558bd25ccdSJames Feist                     [path, owner,
8568bd25ccdSJames Feist                      sensorsAsyncResp](const boost::system::error_code ec,
8578bd25ccdSJames Feist                                        std::variant<std::vector<std::string>>
8588bd25ccdSJames Feist                                            variantEndpoints) {
8598bd25ccdSJames Feist                         if (ec)
8608bd25ccdSJames Feist                         {
8618bd25ccdSJames Feist                             return; // if they don't have an association we
8628bd25ccdSJames Feist                                     // can't tell what chassis is
8638bd25ccdSJames Feist                         }
8648bd25ccdSJames Feist                         // verify part of the right chassis
8658bd25ccdSJames Feist                         auto endpoints = std::get_if<std::vector<std::string>>(
8668bd25ccdSJames Feist                             &variantEndpoints);
8678bd25ccdSJames Feist 
8688bd25ccdSJames Feist                         if (endpoints == nullptr)
8698bd25ccdSJames Feist                         {
8708bd25ccdSJames Feist                             BMCWEB_LOG_ERROR << "Invalid association interface";
8718bd25ccdSJames Feist                             messages::internalError(sensorsAsyncResp->res);
8728bd25ccdSJames Feist                             return;
8738bd25ccdSJames Feist                         }
8748bd25ccdSJames Feist 
8758bd25ccdSJames Feist                         auto found = std::find_if(
8768bd25ccdSJames Feist                             endpoints->begin(), endpoints->end(),
8778bd25ccdSJames Feist                             [sensorsAsyncResp](const std::string& entry) {
8788bd25ccdSJames Feist                                 return entry.find(
8798bd25ccdSJames Feist                                            sensorsAsyncResp->chassisId) !=
8808bd25ccdSJames Feist                                        std::string::npos;
8818bd25ccdSJames Feist                             });
8828bd25ccdSJames Feist 
8838bd25ccdSJames Feist                         if (found == endpoints->end())
8848bd25ccdSJames Feist                         {
8858bd25ccdSJames Feist                             return;
8868bd25ccdSJames Feist                         }
8878bd25ccdSJames Feist                         crow::connections::systemBus->async_method_call(
8888bd25ccdSJames Feist                             [path, sensorsAsyncResp](
8898bd25ccdSJames Feist                                 const boost::system::error_code ec,
8908bd25ccdSJames Feist                                 const boost::container::flat_map<
8918bd25ccdSJames Feist                                     std::string,
8928bd25ccdSJames Feist                                     std::variant<uint8_t,
8938bd25ccdSJames Feist                                                  std::vector<std::string>,
8948bd25ccdSJames Feist                                                  std::string>>& ret) {
8958bd25ccdSJames Feist                                 if (ec)
8968bd25ccdSJames Feist                                 {
8978bd25ccdSJames Feist                                     return; // don't have to have this
8988bd25ccdSJames Feist                                             // interface
8998bd25ccdSJames Feist                                 }
9008bd25ccdSJames Feist                                 auto findFailures = ret.find("AllowedFailures");
9018bd25ccdSJames Feist                                 auto findCollection = ret.find("Collection");
9028bd25ccdSJames Feist                                 auto findStatus = ret.find("Status");
9038bd25ccdSJames Feist 
9048bd25ccdSJames Feist                                 if (findFailures == ret.end() ||
9058bd25ccdSJames Feist                                     findCollection == ret.end() ||
9068bd25ccdSJames Feist                                     findStatus == ret.end())
9078bd25ccdSJames Feist                                 {
9088bd25ccdSJames Feist                                     BMCWEB_LOG_ERROR
9098bd25ccdSJames Feist                                         << "Invalid redundancy interface";
9108bd25ccdSJames Feist                                     messages::internalError(
9118bd25ccdSJames Feist                                         sensorsAsyncResp->res);
9128bd25ccdSJames Feist                                     return;
9138bd25ccdSJames Feist                                 }
9148bd25ccdSJames Feist 
9158bd25ccdSJames Feist                                 auto allowedFailures = std::get_if<uint8_t>(
9168bd25ccdSJames Feist                                     &(findFailures->second));
9178bd25ccdSJames Feist                                 auto collection =
9188bd25ccdSJames Feist                                     std::get_if<std::vector<std::string>>(
9198bd25ccdSJames Feist                                         &(findCollection->second));
9208bd25ccdSJames Feist                                 auto status = std::get_if<std::string>(
9218bd25ccdSJames Feist                                     &(findStatus->second));
9228bd25ccdSJames Feist 
9238bd25ccdSJames Feist                                 if (allowedFailures == nullptr ||
9248bd25ccdSJames Feist                                     collection == nullptr || status == nullptr)
9258bd25ccdSJames Feist                                 {
9268bd25ccdSJames Feist 
9278bd25ccdSJames Feist                                     BMCWEB_LOG_ERROR
9288bd25ccdSJames Feist                                         << "Invalid redundancy interface "
9298bd25ccdSJames Feist                                            "types";
9308bd25ccdSJames Feist                                     messages::internalError(
9318bd25ccdSJames Feist                                         sensorsAsyncResp->res);
9328bd25ccdSJames Feist                                     return;
9338bd25ccdSJames Feist                                 }
9348bd25ccdSJames Feist                                 size_t lastSlash = path.rfind("/");
9358bd25ccdSJames Feist                                 if (lastSlash == std::string::npos)
9368bd25ccdSJames Feist                                 {
9378bd25ccdSJames Feist                                     // this should be impossible
9388bd25ccdSJames Feist                                     messages::internalError(
9398bd25ccdSJames Feist                                         sensorsAsyncResp->res);
9408bd25ccdSJames Feist                                     return;
9418bd25ccdSJames Feist                                 }
9428bd25ccdSJames Feist                                 std::string name = path.substr(lastSlash + 1);
9438bd25ccdSJames Feist                                 std::replace(name.begin(), name.end(), '_',
9448bd25ccdSJames Feist                                              ' ');
9458bd25ccdSJames Feist 
9468bd25ccdSJames Feist                                 std::string health;
9478bd25ccdSJames Feist 
9488bd25ccdSJames Feist                                 if (boost::ends_with(*status, "Full"))
9498bd25ccdSJames Feist                                 {
9508bd25ccdSJames Feist                                     health = "OK";
9518bd25ccdSJames Feist                                 }
9528bd25ccdSJames Feist                                 else if (boost::ends_with(*status, "Degraded"))
9538bd25ccdSJames Feist                                 {
9548bd25ccdSJames Feist                                     health = "Warning";
9558bd25ccdSJames Feist                                 }
9568bd25ccdSJames Feist                                 else
9578bd25ccdSJames Feist                                 {
9588bd25ccdSJames Feist                                     health = "Critical";
9598bd25ccdSJames Feist                                 }
9608bd25ccdSJames Feist                                 std::vector<nlohmann::json> redfishCollection;
9618bd25ccdSJames Feist                                 const auto& fanRedfish =
9628bd25ccdSJames Feist                                     sensorsAsyncResp->res.jsonValue["Fans"];
9638bd25ccdSJames Feist                                 for (const std::string& item : *collection)
9648bd25ccdSJames Feist                                 {
9658bd25ccdSJames Feist                                     lastSlash = item.rfind("/");
9668bd25ccdSJames Feist                                     // make a copy as collection is const
9678bd25ccdSJames Feist                                     std::string itemName =
9688bd25ccdSJames Feist                                         item.substr(lastSlash + 1);
9698bd25ccdSJames Feist                                     /*
9708bd25ccdSJames Feist                                     todo(ed): merge patch that fixes the names
9718bd25ccdSJames Feist                                     std::replace(itemName.begin(),
9728bd25ccdSJames Feist                                                  itemName.end(), '_', ' ');*/
9738bd25ccdSJames Feist                                     auto schemaItem = std::find_if(
9748bd25ccdSJames Feist                                         fanRedfish.begin(), fanRedfish.end(),
9758bd25ccdSJames Feist                                         [itemName](const nlohmann::json& fan) {
9768bd25ccdSJames Feist                                             return fan["MemberId"] == itemName;
9778bd25ccdSJames Feist                                         });
9788bd25ccdSJames Feist                                     if (schemaItem != fanRedfish.end())
9798bd25ccdSJames Feist                                     {
9808bd25ccdSJames Feist                                         redfishCollection.push_back(
9818bd25ccdSJames Feist                                             {{"@odata.id",
9828bd25ccdSJames Feist                                               (*schemaItem)["@odata.id"]}});
9838bd25ccdSJames Feist                                     }
9848bd25ccdSJames Feist                                     else
9858bd25ccdSJames Feist                                     {
9868bd25ccdSJames Feist                                         BMCWEB_LOG_ERROR
9878bd25ccdSJames Feist                                             << "failed to find fan in schema";
9888bd25ccdSJames Feist                                         messages::internalError(
9898bd25ccdSJames Feist                                             sensorsAsyncResp->res);
9908bd25ccdSJames Feist                                         return;
9918bd25ccdSJames Feist                                     }
9928bd25ccdSJames Feist                                 }
9938bd25ccdSJames Feist 
9948bd25ccdSJames Feist                                 auto& resp = sensorsAsyncResp->res
9958bd25ccdSJames Feist                                                  .jsonValue["Redundancy"];
9968bd25ccdSJames Feist                                 resp.push_back(
9978bd25ccdSJames Feist                                     {{"@odata.id",
9988bd25ccdSJames Feist                                       "/refish/v1/Chassis/" +
9998bd25ccdSJames Feist                                           sensorsAsyncResp->chassisId + "/" +
10008bd25ccdSJames Feist                                           sensorsAsyncResp->chassisSubNode +
10018bd25ccdSJames Feist                                           "#/Redundancy/" +
10028bd25ccdSJames Feist                                           std::to_string(resp.size())},
10038bd25ccdSJames Feist                                      {"@odata.type",
10048bd25ccdSJames Feist                                       "#Redundancy.v1_3_2.Redundancy"},
10058bd25ccdSJames Feist                                      {"MinNumNeeded",
10068bd25ccdSJames Feist                                       collection->size() - *allowedFailures},
10078bd25ccdSJames Feist                                      {"MemberId", name},
10088bd25ccdSJames Feist                                      {"Mode", "N+m"},
10098bd25ccdSJames Feist                                      {"Name", name},
10108bd25ccdSJames Feist                                      {"RedundancySet", redfishCollection},
10118bd25ccdSJames Feist                                      {"Status",
10128bd25ccdSJames Feist                                       {{"Health", health},
10138bd25ccdSJames Feist                                        {"State", "Enabled"}}}});
10148bd25ccdSJames Feist                             },
10158bd25ccdSJames Feist                             owner, path, "org.freedesktop.DBus.Properties",
10168bd25ccdSJames Feist                             "GetAll",
10178bd25ccdSJames Feist                             "xyz.openbmc_project.Control.FanRedundancy");
10188bd25ccdSJames Feist                     },
101902e92e32SJames Feist                     "xyz.openbmc_project.ObjectMapper", path + "/chassis",
10208bd25ccdSJames Feist                     "org.freedesktop.DBus.Properties", "Get",
10218bd25ccdSJames Feist                     "xyz.openbmc_project.Association", "endpoints");
10228bd25ccdSJames Feist             }
10238bd25ccdSJames Feist         },
10248bd25ccdSJames Feist         "xyz.openbmc_project.ObjectMapper",
10258bd25ccdSJames Feist         "/xyz/openbmc_project/object_mapper",
10268bd25ccdSJames Feist         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
10278bd25ccdSJames Feist         "/xyz/openbmc_project/control", 2,
10288bd25ccdSJames Feist         std::array<const char*, 1>{
10298bd25ccdSJames Feist             "xyz.openbmc_project.Control.FanRedundancy"});
10308bd25ccdSJames Feist }
10318bd25ccdSJames Feist 
103249c53ac9SJohnathan Mantey void sortJSONResponse(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
103349c53ac9SJohnathan Mantey {
103449c53ac9SJohnathan Mantey     nlohmann::json& response = SensorsAsyncResp->res.jsonValue;
103549c53ac9SJohnathan Mantey     std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
103649c53ac9SJohnathan Mantey     if (SensorsAsyncResp->chassisSubNode == "Power")
103749c53ac9SJohnathan Mantey     {
103849c53ac9SJohnathan Mantey         sensorHeaders = {"Voltages", "PowerSupplies"};
103949c53ac9SJohnathan Mantey     }
104049c53ac9SJohnathan Mantey     for (const std::string& sensorGroup : sensorHeaders)
104149c53ac9SJohnathan Mantey     {
104249c53ac9SJohnathan Mantey         nlohmann::json::iterator entry = response.find(sensorGroup);
104349c53ac9SJohnathan Mantey         if (entry != response.end())
104449c53ac9SJohnathan Mantey         {
104549c53ac9SJohnathan Mantey             std::sort(entry->begin(), entry->end(),
104649c53ac9SJohnathan Mantey                       [](nlohmann::json& c1, nlohmann::json& c2) {
104749c53ac9SJohnathan Mantey                           return c1["Name"] < c2["Name"];
104849c53ac9SJohnathan Mantey                       });
104949c53ac9SJohnathan Mantey 
105049c53ac9SJohnathan Mantey             // add the index counts to the end of each entry
105149c53ac9SJohnathan Mantey             size_t count = 0;
105249c53ac9SJohnathan Mantey             for (nlohmann::json& sensorJson : *entry)
105349c53ac9SJohnathan Mantey             {
105449c53ac9SJohnathan Mantey                 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
105549c53ac9SJohnathan Mantey                 if (odata == sensorJson.end())
105649c53ac9SJohnathan Mantey                 {
105749c53ac9SJohnathan Mantey                     continue;
105849c53ac9SJohnathan Mantey                 }
105949c53ac9SJohnathan Mantey                 std::string* value = odata->get_ptr<std::string*>();
106049c53ac9SJohnathan Mantey                 if (value != nullptr)
106149c53ac9SJohnathan Mantey                 {
106249c53ac9SJohnathan Mantey                     *value += std::to_string(count);
106349c53ac9SJohnathan Mantey                     count++;
106449c53ac9SJohnathan Mantey                 }
106549c53ac9SJohnathan Mantey             }
106649c53ac9SJohnathan Mantey         }
106749c53ac9SJohnathan Mantey     }
106849c53ac9SJohnathan Mantey }
106949c53ac9SJohnathan Mantey 
107008777fb0SLewanczyk, Dawid /**
1071adc4f0dbSShawn McCarney  * @brief Finds the inventory item with the specified object path.
1072adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
1073adc4f0dbSShawn McCarney  * @param invItemObjPath D-Bus object path of inventory item.
1074adc4f0dbSShawn McCarney  * @return Inventory item within vector, or nullptr if no match found.
10758fb49dd6SShawn McCarney  */
1076adc4f0dbSShawn McCarney static InventoryItem* findInventoryItem(
1077adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1078adc4f0dbSShawn McCarney     const std::string& invItemObjPath)
10798fb49dd6SShawn McCarney {
1080adc4f0dbSShawn McCarney     for (InventoryItem& inventoryItem : *inventoryItems)
10818fb49dd6SShawn McCarney     {
1082adc4f0dbSShawn McCarney         if (inventoryItem.objectPath == invItemObjPath)
10838fb49dd6SShawn McCarney         {
1084adc4f0dbSShawn McCarney             return &inventoryItem;
10858fb49dd6SShawn McCarney         }
10868fb49dd6SShawn McCarney     }
10878fb49dd6SShawn McCarney     return nullptr;
10888fb49dd6SShawn McCarney }
10898fb49dd6SShawn McCarney 
10908fb49dd6SShawn McCarney /**
1091adc4f0dbSShawn McCarney  * @brief Finds the inventory item associated with the specified sensor.
1092adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
1093adc4f0dbSShawn McCarney  * @param sensorObjPath D-Bus object path of sensor.
1094adc4f0dbSShawn McCarney  * @return Inventory item within vector, or nullptr if no match found.
10958fb49dd6SShawn McCarney  */
1096adc4f0dbSShawn McCarney static InventoryItem* findInventoryItemForSensor(
1097adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1098adc4f0dbSShawn McCarney     const std::string& sensorObjPath)
1099adc4f0dbSShawn McCarney {
1100adc4f0dbSShawn McCarney     for (InventoryItem& inventoryItem : *inventoryItems)
1101adc4f0dbSShawn McCarney     {
1102adc4f0dbSShawn McCarney         if (inventoryItem.sensors.count(sensorObjPath) > 0)
1103adc4f0dbSShawn McCarney         {
1104adc4f0dbSShawn McCarney             return &inventoryItem;
1105adc4f0dbSShawn McCarney         }
1106adc4f0dbSShawn McCarney     }
1107adc4f0dbSShawn McCarney     return nullptr;
1108adc4f0dbSShawn McCarney }
1109adc4f0dbSShawn McCarney 
1110adc4f0dbSShawn McCarney /**
1111adc4f0dbSShawn McCarney  * @brief Adds inventory item and associated sensor to specified vector.
1112adc4f0dbSShawn McCarney  *
1113adc4f0dbSShawn McCarney  * Adds a new InventoryItem to the vector if necessary.  Searches for an
1114adc4f0dbSShawn McCarney  * existing InventoryItem with the specified object path.  If not found, one is
1115adc4f0dbSShawn McCarney  * added to the vector.
1116adc4f0dbSShawn McCarney  *
1117adc4f0dbSShawn McCarney  * Next, the specified sensor is added to the set of sensors associated with the
1118adc4f0dbSShawn McCarney  * InventoryItem.
1119adc4f0dbSShawn McCarney  *
1120adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
1121adc4f0dbSShawn McCarney  * @param invItemObjPath D-Bus object path of inventory item.
1122adc4f0dbSShawn McCarney  * @param sensorObjPath D-Bus object path of sensor
1123adc4f0dbSShawn McCarney  */
1124adc4f0dbSShawn McCarney static void
1125adc4f0dbSShawn McCarney     addInventoryItem(std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1126adc4f0dbSShawn McCarney                      const std::string& invItemObjPath,
1127adc4f0dbSShawn McCarney                      const std::string& sensorObjPath)
1128adc4f0dbSShawn McCarney {
1129adc4f0dbSShawn McCarney     // Look for inventory item in vector
1130adc4f0dbSShawn McCarney     InventoryItem* inventoryItem =
1131adc4f0dbSShawn McCarney         findInventoryItem(inventoryItems, invItemObjPath);
1132adc4f0dbSShawn McCarney 
1133adc4f0dbSShawn McCarney     // If inventory item doesn't exist in vector, add it
1134adc4f0dbSShawn McCarney     if (inventoryItem == nullptr)
1135adc4f0dbSShawn McCarney     {
1136adc4f0dbSShawn McCarney         inventoryItems->emplace_back(invItemObjPath);
1137adc4f0dbSShawn McCarney         inventoryItem = &(inventoryItems->back());
1138adc4f0dbSShawn McCarney     }
1139adc4f0dbSShawn McCarney 
1140adc4f0dbSShawn McCarney     // Add sensor to set of sensors associated with inventory item
1141adc4f0dbSShawn McCarney     inventoryItem->sensors.emplace(sensorObjPath);
1142adc4f0dbSShawn McCarney }
1143adc4f0dbSShawn McCarney 
1144adc4f0dbSShawn McCarney /**
1145adc4f0dbSShawn McCarney  * @brief Stores D-Bus data in the specified inventory item.
1146adc4f0dbSShawn McCarney  *
1147adc4f0dbSShawn McCarney  * Finds D-Bus data in the specified map of interfaces.  Stores the data in the
1148adc4f0dbSShawn McCarney  * specified InventoryItem.
1149adc4f0dbSShawn McCarney  *
1150adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
1151adc4f0dbSShawn McCarney  * response.
1152adc4f0dbSShawn McCarney  *
1153adc4f0dbSShawn McCarney  * @param inventoryItem Inventory item where data will be stored.
1154adc4f0dbSShawn McCarney  * @param interfacesDict Map containing D-Bus interfaces and their properties
1155adc4f0dbSShawn McCarney  * for the specified inventory item.
1156adc4f0dbSShawn McCarney  */
1157adc4f0dbSShawn McCarney static void storeInventoryItemData(
1158adc4f0dbSShawn McCarney     InventoryItem& inventoryItem,
11598fb49dd6SShawn McCarney     const boost::container::flat_map<
11608fb49dd6SShawn McCarney         std::string, boost::container::flat_map<std::string, SensorVariant>>&
11618fb49dd6SShawn McCarney         interfacesDict)
11628fb49dd6SShawn McCarney {
1163adc4f0dbSShawn McCarney     // Get properties from Inventory.Item interface
1164adc4f0dbSShawn McCarney     auto interfaceIt =
1165adc4f0dbSShawn McCarney         interfacesDict.find("xyz.openbmc_project.Inventory.Item");
1166adc4f0dbSShawn McCarney     if (interfaceIt != interfacesDict.end())
11678fb49dd6SShawn McCarney     {
1168adc4f0dbSShawn McCarney         auto propertyIt = interfaceIt->second.find("Present");
1169adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
11708fb49dd6SShawn McCarney         {
1171adc4f0dbSShawn McCarney             const bool* value = std::get_if<bool>(&propertyIt->second);
1172adc4f0dbSShawn McCarney             if (value != nullptr)
11738fb49dd6SShawn McCarney             {
1174adc4f0dbSShawn McCarney                 inventoryItem.isPresent = *value;
11758fb49dd6SShawn McCarney             }
11768fb49dd6SShawn McCarney         }
11778fb49dd6SShawn McCarney     }
11788fb49dd6SShawn McCarney 
1179adc4f0dbSShawn McCarney     // Check if Inventory.Item.PowerSupply interface is present
1180adc4f0dbSShawn McCarney     interfaceIt =
1181adc4f0dbSShawn McCarney         interfacesDict.find("xyz.openbmc_project.Inventory.Item.PowerSupply");
1182adc4f0dbSShawn McCarney     if (interfaceIt != interfacesDict.end())
11838fb49dd6SShawn McCarney     {
1184adc4f0dbSShawn McCarney         inventoryItem.isPowerSupply = true;
11858fb49dd6SShawn McCarney     }
1186adc4f0dbSShawn McCarney 
1187adc4f0dbSShawn McCarney     // Get properties from Inventory.Decorator.Asset interface
1188adc4f0dbSShawn McCarney     interfaceIt =
1189adc4f0dbSShawn McCarney         interfacesDict.find("xyz.openbmc_project.Inventory.Decorator.Asset");
1190adc4f0dbSShawn McCarney     if (interfaceIt != interfacesDict.end())
1191adc4f0dbSShawn McCarney     {
1192adc4f0dbSShawn McCarney         auto propertyIt = interfaceIt->second.find("Manufacturer");
1193adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1194adc4f0dbSShawn McCarney         {
1195adc4f0dbSShawn McCarney             const std::string* value =
1196adc4f0dbSShawn McCarney                 std::get_if<std::string>(&propertyIt->second);
1197adc4f0dbSShawn McCarney             if (value != nullptr)
1198adc4f0dbSShawn McCarney             {
1199adc4f0dbSShawn McCarney                 inventoryItem.manufacturer = *value;
1200adc4f0dbSShawn McCarney             }
1201adc4f0dbSShawn McCarney         }
1202adc4f0dbSShawn McCarney 
1203adc4f0dbSShawn McCarney         propertyIt = interfaceIt->second.find("Model");
1204adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1205adc4f0dbSShawn McCarney         {
1206adc4f0dbSShawn McCarney             const std::string* value =
1207adc4f0dbSShawn McCarney                 std::get_if<std::string>(&propertyIt->second);
1208adc4f0dbSShawn McCarney             if (value != nullptr)
1209adc4f0dbSShawn McCarney             {
1210adc4f0dbSShawn McCarney                 inventoryItem.model = *value;
1211adc4f0dbSShawn McCarney             }
1212adc4f0dbSShawn McCarney         }
1213adc4f0dbSShawn McCarney 
1214adc4f0dbSShawn McCarney         propertyIt = interfaceIt->second.find("PartNumber");
1215adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1216adc4f0dbSShawn McCarney         {
1217adc4f0dbSShawn McCarney             const std::string* value =
1218adc4f0dbSShawn McCarney                 std::get_if<std::string>(&propertyIt->second);
1219adc4f0dbSShawn McCarney             if (value != nullptr)
1220adc4f0dbSShawn McCarney             {
1221adc4f0dbSShawn McCarney                 inventoryItem.partNumber = *value;
1222adc4f0dbSShawn McCarney             }
1223adc4f0dbSShawn McCarney         }
1224adc4f0dbSShawn McCarney 
1225adc4f0dbSShawn McCarney         propertyIt = interfaceIt->second.find("SerialNumber");
1226adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1227adc4f0dbSShawn McCarney         {
1228adc4f0dbSShawn McCarney             const std::string* value =
1229adc4f0dbSShawn McCarney                 std::get_if<std::string>(&propertyIt->second);
1230adc4f0dbSShawn McCarney             if (value != nullptr)
1231adc4f0dbSShawn McCarney             {
1232adc4f0dbSShawn McCarney                 inventoryItem.serialNumber = *value;
1233adc4f0dbSShawn McCarney             }
1234adc4f0dbSShawn McCarney         }
1235adc4f0dbSShawn McCarney     }
1236adc4f0dbSShawn McCarney 
1237adc4f0dbSShawn McCarney     // Get properties from State.Decorator.OperationalStatus interface
1238adc4f0dbSShawn McCarney     interfaceIt = interfacesDict.find(
1239adc4f0dbSShawn McCarney         "xyz.openbmc_project.State.Decorator.OperationalStatus");
1240adc4f0dbSShawn McCarney     if (interfaceIt != interfacesDict.end())
1241adc4f0dbSShawn McCarney     {
1242adc4f0dbSShawn McCarney         auto propertyIt = interfaceIt->second.find("Functional");
1243adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1244adc4f0dbSShawn McCarney         {
1245adc4f0dbSShawn McCarney             const bool* value = std::get_if<bool>(&propertyIt->second);
1246adc4f0dbSShawn McCarney             if (value != nullptr)
1247adc4f0dbSShawn McCarney             {
1248adc4f0dbSShawn McCarney                 inventoryItem.isFunctional = *value;
12498fb49dd6SShawn McCarney             }
12508fb49dd6SShawn McCarney         }
12518fb49dd6SShawn McCarney     }
12528fb49dd6SShawn McCarney }
12538fb49dd6SShawn McCarney 
12548fb49dd6SShawn McCarney /**
1255adc4f0dbSShawn McCarney  * @brief Gets D-Bus data for inventory items associated with sensors.
12568fb49dd6SShawn McCarney  *
1257adc4f0dbSShawn McCarney  * Uses the specified connections (services) to obtain D-Bus data for inventory
1258adc4f0dbSShawn McCarney  * items associated with sensors.  Stores the resulting data in the
1259adc4f0dbSShawn McCarney  * inventoryItems vector.
12608fb49dd6SShawn McCarney  *
1261adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
1262adc4f0dbSShawn McCarney  * response.
1263adc4f0dbSShawn McCarney  *
1264adc4f0dbSShawn McCarney  * Finds the inventory item data asynchronously.  Invokes callback when data has
1265adc4f0dbSShawn McCarney  * been obtained.
1266adc4f0dbSShawn McCarney  *
1267adc4f0dbSShawn McCarney  * The callback must have the following signature:
1268adc4f0dbSShawn McCarney  *   @code
1269adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1270adc4f0dbSShawn McCarney  *   @endcode
1271adc4f0dbSShawn McCarney  *
1272adc4f0dbSShawn McCarney  * This function is called recursively, obtaining data asynchronously from one
1273adc4f0dbSShawn McCarney  * connection in each call.  This ensures the callback is not invoked until the
1274adc4f0dbSShawn McCarney  * last asynchronous function has completed.
12758fb49dd6SShawn McCarney  *
12768fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
1277adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
1278adc4f0dbSShawn McCarney  * @param invConnections Connections that provide data for the inventory items.
12798fb49dd6SShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
12808fb49dd6SShawn McCarney  * implements ObjectManager.
1281adc4f0dbSShawn McCarney  * @param callback Callback to invoke when inventory data has been obtained.
1282adc4f0dbSShawn McCarney  * @param invConnectionsIndex Current index in invConnections.  Only specified
1283adc4f0dbSShawn McCarney  * in recursive calls to this function.
12848fb49dd6SShawn McCarney  */
1285adc4f0dbSShawn McCarney template <typename Callback>
1286adc4f0dbSShawn McCarney static void getInventoryItemsData(
12878fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1288adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
12898fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_set<std::string>> invConnections,
12908fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1291adc4f0dbSShawn McCarney         objectMgrPaths,
1292adc4f0dbSShawn McCarney     Callback&& callback, int invConnectionsIndex = 0)
12938fb49dd6SShawn McCarney {
1294adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsData enter";
12958fb49dd6SShawn McCarney 
1296adc4f0dbSShawn McCarney     // If no more connections left, call callback
1297adc4f0dbSShawn McCarney     if (invConnectionsIndex >= invConnections->size())
12988fb49dd6SShawn McCarney     {
1299adc4f0dbSShawn McCarney         callback(inventoryItems);
1300adc4f0dbSShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemsData exit";
1301adc4f0dbSShawn McCarney         return;
1302adc4f0dbSShawn McCarney     }
1303adc4f0dbSShawn McCarney 
1304adc4f0dbSShawn McCarney     // Get inventory item data from current connection
1305adc4f0dbSShawn McCarney     auto it = invConnections->nth(invConnectionsIndex);
1306adc4f0dbSShawn McCarney     if (it != invConnections->end())
1307adc4f0dbSShawn McCarney     {
1308adc4f0dbSShawn McCarney         const std::string& invConnection = *it;
1309adc4f0dbSShawn McCarney 
13108fb49dd6SShawn McCarney         // Response handler for GetManagedObjects
1311adc4f0dbSShawn McCarney         auto respHandler = [sensorsAsyncResp, inventoryItems, invConnections,
1312adc4f0dbSShawn McCarney                             objectMgrPaths, callback{std::move(callback)},
1313adc4f0dbSShawn McCarney                             invConnectionsIndex](
1314adc4f0dbSShawn McCarney                                const boost::system::error_code ec,
13158fb49dd6SShawn McCarney                                ManagedObjectsVectorType& resp) {
1316adc4f0dbSShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemsData respHandler enter";
13178fb49dd6SShawn McCarney             if (ec)
13188fb49dd6SShawn McCarney             {
13198fb49dd6SShawn McCarney                 BMCWEB_LOG_ERROR
1320adc4f0dbSShawn McCarney                     << "getInventoryItemsData respHandler DBus error " << ec;
13218fb49dd6SShawn McCarney                 messages::internalError(sensorsAsyncResp->res);
13228fb49dd6SShawn McCarney                 return;
13238fb49dd6SShawn McCarney             }
13248fb49dd6SShawn McCarney 
13258fb49dd6SShawn McCarney             // Loop through returned object paths
13268fb49dd6SShawn McCarney             for (const auto& objDictEntry : resp)
13278fb49dd6SShawn McCarney             {
13288fb49dd6SShawn McCarney                 const std::string& objPath =
13298fb49dd6SShawn McCarney                     static_cast<const std::string&>(objDictEntry.first);
13308fb49dd6SShawn McCarney 
1331adc4f0dbSShawn McCarney                 // If this object path is one of the specified inventory items
1332adc4f0dbSShawn McCarney                 InventoryItem* inventoryItem =
1333adc4f0dbSShawn McCarney                     findInventoryItem(inventoryItems, objPath);
1334adc4f0dbSShawn McCarney                 if (inventoryItem != nullptr)
13358fb49dd6SShawn McCarney                 {
1336adc4f0dbSShawn McCarney                     // Store inventory data in InventoryItem
1337adc4f0dbSShawn McCarney                     storeInventoryItemData(*inventoryItem, objDictEntry.second);
13388fb49dd6SShawn McCarney                 }
13398fb49dd6SShawn McCarney             }
13408fb49dd6SShawn McCarney 
1341adc4f0dbSShawn McCarney             // Recurse to get inventory item data from next connection
1342adc4f0dbSShawn McCarney             getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1343adc4f0dbSShawn McCarney                                   invConnections, objectMgrPaths,
1344adc4f0dbSShawn McCarney                                   std::move(callback), invConnectionsIndex + 1);
1345adc4f0dbSShawn McCarney 
1346adc4f0dbSShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemsData respHandler exit";
13478fb49dd6SShawn McCarney         };
13488fb49dd6SShawn McCarney 
13498fb49dd6SShawn McCarney         // Find DBus object path that implements ObjectManager for the current
13508fb49dd6SShawn McCarney         // connection.  If no mapping found, default to "/".
13518fb49dd6SShawn McCarney         auto iter = objectMgrPaths->find(invConnection);
13528fb49dd6SShawn McCarney         const std::string& objectMgrPath =
13538fb49dd6SShawn McCarney             (iter != objectMgrPaths->end()) ? iter->second : "/";
13548fb49dd6SShawn McCarney         BMCWEB_LOG_DEBUG << "ObjectManager path for " << invConnection << " is "
13558fb49dd6SShawn McCarney                          << objectMgrPath;
13568fb49dd6SShawn McCarney 
13578fb49dd6SShawn McCarney         // Get all object paths and their interfaces for current connection
13588fb49dd6SShawn McCarney         crow::connections::systemBus->async_method_call(
13598fb49dd6SShawn McCarney             std::move(respHandler), invConnection, objectMgrPath,
13608fb49dd6SShawn McCarney             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
13618fb49dd6SShawn McCarney     }
13628fb49dd6SShawn McCarney 
1363adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsData exit";
13648fb49dd6SShawn McCarney }
13658fb49dd6SShawn McCarney 
13668fb49dd6SShawn McCarney /**
1367adc4f0dbSShawn McCarney  * @brief Gets connections that provide D-Bus data for inventory items.
13688fb49dd6SShawn McCarney  *
1369adc4f0dbSShawn McCarney  * Gets the D-Bus connections (services) that provide data for the inventory
1370adc4f0dbSShawn McCarney  * items that are associated with sensors.
13718fb49dd6SShawn McCarney  *
13728fb49dd6SShawn McCarney  * Finds the connections asynchronously.  Invokes callback when information has
13738fb49dd6SShawn McCarney  * been obtained.
13748fb49dd6SShawn McCarney  *
13758fb49dd6SShawn McCarney  * The callback must have the following signature:
13768fb49dd6SShawn McCarney  *   @code
13778fb49dd6SShawn McCarney  *   callback(std::shared_ptr<boost::container::flat_set<std::string>>
13788fb49dd6SShawn McCarney  *            invConnections)
13798fb49dd6SShawn McCarney  *   @endcode
13808fb49dd6SShawn McCarney  *
13818fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
1382adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
13838fb49dd6SShawn McCarney  * @param callback Callback to invoke when connections have been obtained.
13848fb49dd6SShawn McCarney  */
13858fb49dd6SShawn McCarney template <typename Callback>
13868fb49dd6SShawn McCarney static void getInventoryItemsConnections(
13878fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1388adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
13898fb49dd6SShawn McCarney     Callback&& callback)
13908fb49dd6SShawn McCarney {
13918fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsConnections enter";
13928fb49dd6SShawn McCarney 
13938fb49dd6SShawn McCarney     const std::string path = "/xyz/openbmc_project/inventory";
1394adc4f0dbSShawn McCarney     const std::array<std::string, 4> interfaces = {
13958fb49dd6SShawn McCarney         "xyz.openbmc_project.Inventory.Item",
1396adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Item.PowerSupply",
1397adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Decorator.Asset",
13988fb49dd6SShawn McCarney         "xyz.openbmc_project.State.Decorator.OperationalStatus"};
13998fb49dd6SShawn McCarney 
14008fb49dd6SShawn McCarney     // Response handler for parsing output from GetSubTree
14018fb49dd6SShawn McCarney     auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
1402adc4f0dbSShawn McCarney                         inventoryItems](const boost::system::error_code ec,
14038fb49dd6SShawn McCarney                                         const GetSubTreeType& subtree) {
14048fb49dd6SShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler enter";
14058fb49dd6SShawn McCarney         if (ec)
14068fb49dd6SShawn McCarney         {
14078fb49dd6SShawn McCarney             messages::internalError(sensorsAsyncResp->res);
14088fb49dd6SShawn McCarney             BMCWEB_LOG_ERROR
14098fb49dd6SShawn McCarney                 << "getInventoryItemsConnections respHandler DBus error " << ec;
14108fb49dd6SShawn McCarney             return;
14118fb49dd6SShawn McCarney         }
14128fb49dd6SShawn McCarney 
14138fb49dd6SShawn McCarney         // Make unique list of connections for desired inventory items
14148fb49dd6SShawn McCarney         std::shared_ptr<boost::container::flat_set<std::string>>
14158fb49dd6SShawn McCarney             invConnections =
14168fb49dd6SShawn McCarney                 std::make_shared<boost::container::flat_set<std::string>>();
14178fb49dd6SShawn McCarney         invConnections->reserve(8);
14188fb49dd6SShawn McCarney 
14198fb49dd6SShawn McCarney         // Loop through objects from GetSubTree
14208fb49dd6SShawn McCarney         for (const std::pair<
14218fb49dd6SShawn McCarney                  std::string,
14228fb49dd6SShawn McCarney                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
14238fb49dd6SShawn McCarney                  object : subtree)
14248fb49dd6SShawn McCarney         {
1425adc4f0dbSShawn McCarney             // Check if object path is one of the specified inventory items
14268fb49dd6SShawn McCarney             const std::string& objPath = object.first;
1427adc4f0dbSShawn McCarney             if (findInventoryItem(inventoryItems, objPath) != nullptr)
14288fb49dd6SShawn McCarney             {
14298fb49dd6SShawn McCarney                 // Store all connections to inventory item
14308fb49dd6SShawn McCarney                 for (const std::pair<std::string, std::vector<std::string>>&
14318fb49dd6SShawn McCarney                          objData : object.second)
14328fb49dd6SShawn McCarney                 {
14338fb49dd6SShawn McCarney                     const std::string& invConnection = objData.first;
14348fb49dd6SShawn McCarney                     invConnections->insert(invConnection);
14358fb49dd6SShawn McCarney                 }
14368fb49dd6SShawn McCarney             }
14378fb49dd6SShawn McCarney         }
14388fb49dd6SShawn McCarney         callback(invConnections);
14398fb49dd6SShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler exit";
14408fb49dd6SShawn McCarney     };
14418fb49dd6SShawn McCarney 
14428fb49dd6SShawn McCarney     // Make call to ObjectMapper to find all inventory items
14438fb49dd6SShawn McCarney     crow::connections::systemBus->async_method_call(
14448fb49dd6SShawn McCarney         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
14458fb49dd6SShawn McCarney         "/xyz/openbmc_project/object_mapper",
14468fb49dd6SShawn McCarney         "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 0, interfaces);
14478fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsConnections exit";
14488fb49dd6SShawn McCarney }
14498fb49dd6SShawn McCarney 
14508fb49dd6SShawn McCarney /**
1451adc4f0dbSShawn McCarney  * @brief Gets associations from sensors to inventory items.
14528fb49dd6SShawn McCarney  *
14538fb49dd6SShawn McCarney  * Looks for ObjectMapper associations from the specified sensors to related
1454adc4f0dbSShawn McCarney  * inventory items.
14558fb49dd6SShawn McCarney  *
14568fb49dd6SShawn McCarney  * Finds the inventory items asynchronously.  Invokes callback when information
14578fb49dd6SShawn McCarney  * has been obtained.
14588fb49dd6SShawn McCarney  *
14598fb49dd6SShawn McCarney  * The callback must have the following signature:
14608fb49dd6SShawn McCarney  *   @code
1461adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
14628fb49dd6SShawn McCarney  *   @endcode
14638fb49dd6SShawn McCarney  *
14648fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
14658fb49dd6SShawn McCarney  * @param sensorNames All sensors within the current chassis.
14668fb49dd6SShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
14678fb49dd6SShawn McCarney  * implements ObjectManager.
14688fb49dd6SShawn McCarney  * @param callback Callback to invoke when inventory items have been obtained.
14698fb49dd6SShawn McCarney  */
14708fb49dd6SShawn McCarney template <typename Callback>
1471adc4f0dbSShawn McCarney static void getInventoryItemAssociations(
14728fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
14738fb49dd6SShawn McCarney     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
14748fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
14758fb49dd6SShawn McCarney         objectMgrPaths,
14768fb49dd6SShawn McCarney     Callback&& callback)
14778fb49dd6SShawn McCarney {
1478adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemAssociations enter";
14798fb49dd6SShawn McCarney 
14808fb49dd6SShawn McCarney     // Response handler for GetManagedObjects
14818fb49dd6SShawn McCarney     auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
14828fb49dd6SShawn McCarney                         sensorNames](const boost::system::error_code ec,
14838fb49dd6SShawn McCarney                                      dbus::utility::ManagedObjectType& resp) {
1484adc4f0dbSShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemAssociations respHandler enter";
14858fb49dd6SShawn McCarney         if (ec)
14868fb49dd6SShawn McCarney         {
1487adc4f0dbSShawn McCarney             BMCWEB_LOG_ERROR
1488adc4f0dbSShawn McCarney                 << "getInventoryItemAssociations respHandler DBus error " << ec;
14898fb49dd6SShawn McCarney             messages::internalError(sensorsAsyncResp->res);
14908fb49dd6SShawn McCarney             return;
14918fb49dd6SShawn McCarney         }
14928fb49dd6SShawn McCarney 
1493adc4f0dbSShawn McCarney         // Create vector to hold list of inventory items
1494adc4f0dbSShawn McCarney         std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1495adc4f0dbSShawn McCarney             std::make_shared<std::vector<InventoryItem>>();
1496adc4f0dbSShawn McCarney 
14978fb49dd6SShawn McCarney         // Loop through returned object paths
14988fb49dd6SShawn McCarney         std::string sensorAssocPath;
14998fb49dd6SShawn McCarney         sensorAssocPath.reserve(128); // avoid memory allocations
15008fb49dd6SShawn McCarney         for (const auto& objDictEntry : resp)
15018fb49dd6SShawn McCarney         {
15028fb49dd6SShawn McCarney             const std::string& objPath =
15038fb49dd6SShawn McCarney                 static_cast<const std::string&>(objDictEntry.first);
15048fb49dd6SShawn McCarney             const boost::container::flat_map<
15058fb49dd6SShawn McCarney                 std::string, boost::container::flat_map<
15068fb49dd6SShawn McCarney                                  std::string, dbus::utility::DbusVariantType>>&
15078fb49dd6SShawn McCarney                 interfacesDict = objDictEntry.second;
15088fb49dd6SShawn McCarney 
15098fb49dd6SShawn McCarney             // If path is inventory association for one of the specified sensors
15108fb49dd6SShawn McCarney             for (const std::string& sensorName : *sensorNames)
15118fb49dd6SShawn McCarney             {
15128fb49dd6SShawn McCarney                 sensorAssocPath = sensorName;
15138fb49dd6SShawn McCarney                 sensorAssocPath += "/inventory";
15148fb49dd6SShawn McCarney                 if (objPath == sensorAssocPath)
15158fb49dd6SShawn McCarney                 {
15168fb49dd6SShawn McCarney                     // Get Association interface for object path
15178fb49dd6SShawn McCarney                     auto assocIt =
15188fb49dd6SShawn McCarney                         interfacesDict.find("xyz.openbmc_project.Association");
15198fb49dd6SShawn McCarney                     if (assocIt != interfacesDict.end())
15208fb49dd6SShawn McCarney                     {
15218fb49dd6SShawn McCarney                         // Get inventory item from end point
15228fb49dd6SShawn McCarney                         auto endpointsIt = assocIt->second.find("endpoints");
15238fb49dd6SShawn McCarney                         if (endpointsIt != assocIt->second.end())
15248fb49dd6SShawn McCarney                         {
15258fb49dd6SShawn McCarney                             const std::vector<std::string>* endpoints =
15268fb49dd6SShawn McCarney                                 std::get_if<std::vector<std::string>>(
15278fb49dd6SShawn McCarney                                     &endpointsIt->second);
15288fb49dd6SShawn McCarney                             if ((endpoints != nullptr) && !endpoints->empty())
15298fb49dd6SShawn McCarney                             {
1530adc4f0dbSShawn McCarney                                 // Add inventory item to vector
1531adc4f0dbSShawn McCarney                                 const std::string& invItemPath =
1532adc4f0dbSShawn McCarney                                     endpoints->front();
1533adc4f0dbSShawn McCarney                                 addInventoryItem(inventoryItems, invItemPath,
1534adc4f0dbSShawn McCarney                                                  sensorName);
15358fb49dd6SShawn McCarney                             }
15368fb49dd6SShawn McCarney                         }
15378fb49dd6SShawn McCarney                     }
15388fb49dd6SShawn McCarney                     break;
15398fb49dd6SShawn McCarney                 }
15408fb49dd6SShawn McCarney             }
15418fb49dd6SShawn McCarney         }
15428fb49dd6SShawn McCarney 
1543adc4f0dbSShawn McCarney         callback(inventoryItems);
1544adc4f0dbSShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemAssociations respHandler exit";
15458fb49dd6SShawn McCarney     };
15468fb49dd6SShawn McCarney 
15478fb49dd6SShawn McCarney     // Find DBus object path that implements ObjectManager for ObjectMapper
15488fb49dd6SShawn McCarney     std::string connection = "xyz.openbmc_project.ObjectMapper";
15498fb49dd6SShawn McCarney     auto iter = objectMgrPaths->find(connection);
15508fb49dd6SShawn McCarney     const std::string& objectMgrPath =
15518fb49dd6SShawn McCarney         (iter != objectMgrPaths->end()) ? iter->second : "/";
15528fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
15538fb49dd6SShawn McCarney                      << objectMgrPath;
15548fb49dd6SShawn McCarney 
15558fb49dd6SShawn McCarney     // Call GetManagedObjects on the ObjectMapper to get all associations
15568fb49dd6SShawn McCarney     crow::connections::systemBus->async_method_call(
15578fb49dd6SShawn McCarney         std::move(respHandler), connection, objectMgrPath,
15588fb49dd6SShawn McCarney         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
15598fb49dd6SShawn McCarney 
1560adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemAssociations exit";
15618fb49dd6SShawn McCarney }
15628fb49dd6SShawn McCarney 
15638fb49dd6SShawn McCarney /**
1564adc4f0dbSShawn McCarney  * @brief Gets inventory items associated with sensors.
15658fb49dd6SShawn McCarney  *
15668fb49dd6SShawn McCarney  * Finds the inventory items that are associated with the specified sensors.
1567adc4f0dbSShawn McCarney  * Then gets D-Bus data for the inventory items, such as presence and VPD.
15688fb49dd6SShawn McCarney  *
1569adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
1570adc4f0dbSShawn McCarney  * response.
15718fb49dd6SShawn McCarney  *
1572adc4f0dbSShawn McCarney  * Finds the inventory items asynchronously.  Invokes callback when the
1573adc4f0dbSShawn McCarney  * inventory items have been obtained.
1574adc4f0dbSShawn McCarney  *
1575adc4f0dbSShawn McCarney  * The callback must have the following signature:
1576adc4f0dbSShawn McCarney  *   @code
1577adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1578adc4f0dbSShawn McCarney  *   @endcode
15798fb49dd6SShawn McCarney  *
15808fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
15818fb49dd6SShawn McCarney  * @param sensorNames All sensors within the current chassis.
15828fb49dd6SShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
15838fb49dd6SShawn McCarney  * implements ObjectManager.
1584adc4f0dbSShawn McCarney  * @param callback Callback to invoke when inventory items have been obtained.
15858fb49dd6SShawn McCarney  */
1586adc4f0dbSShawn McCarney template <typename Callback>
1587adc4f0dbSShawn McCarney static void getInventoryItems(
15888fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
15898fb49dd6SShawn McCarney     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
15908fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1591adc4f0dbSShawn McCarney         objectMgrPaths,
1592adc4f0dbSShawn McCarney     Callback&& callback)
15938fb49dd6SShawn McCarney {
1594adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItems enter";
1595adc4f0dbSShawn McCarney     auto getInventoryItemAssociationsCb =
1596adc4f0dbSShawn McCarney         [sensorsAsyncResp, objectMgrPaths, callback{std::move(callback)}](
1597adc4f0dbSShawn McCarney             std::shared_ptr<std::vector<InventoryItem>> inventoryItems) {
1598adc4f0dbSShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemAssociationsCb enter";
15998fb49dd6SShawn McCarney             auto getInventoryItemsConnectionsCb =
1600adc4f0dbSShawn McCarney                 [sensorsAsyncResp, inventoryItems, objectMgrPaths,
1601adc4f0dbSShawn McCarney                  callback{std::move(callback)}](
16028fb49dd6SShawn McCarney                     std::shared_ptr<boost::container::flat_set<std::string>>
16038fb49dd6SShawn McCarney                         invConnections) {
16048fb49dd6SShawn McCarney                     BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb enter";
16058fb49dd6SShawn McCarney 
1606adc4f0dbSShawn McCarney                     // Get inventory item data from connections
1607adc4f0dbSShawn McCarney                     getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1608adc4f0dbSShawn McCarney                                           invConnections, objectMgrPaths,
1609adc4f0dbSShawn McCarney                                           std::move(callback));
16108fb49dd6SShawn McCarney 
16118fb49dd6SShawn McCarney                     BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb exit";
16128fb49dd6SShawn McCarney                 };
16138fb49dd6SShawn McCarney 
1614adc4f0dbSShawn McCarney             // Get connections that provide inventory item data
16158fb49dd6SShawn McCarney             getInventoryItemsConnections(
1616adc4f0dbSShawn McCarney                 sensorsAsyncResp, inventoryItems,
16178fb49dd6SShawn McCarney                 std::move(getInventoryItemsConnectionsCb));
1618adc4f0dbSShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemAssociationsCb exit";
16198fb49dd6SShawn McCarney         };
16208fb49dd6SShawn McCarney 
1621adc4f0dbSShawn McCarney     // Get associations from sensors to inventory items
1622adc4f0dbSShawn McCarney     getInventoryItemAssociations(sensorsAsyncResp, sensorNames, objectMgrPaths,
1623adc4f0dbSShawn McCarney                                  std::move(getInventoryItemAssociationsCb));
1624adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItems exit";
1625adc4f0dbSShawn McCarney }
1626adc4f0dbSShawn McCarney 
1627adc4f0dbSShawn McCarney /**
1628adc4f0dbSShawn McCarney  * @brief Returns JSON PowerSupply object for the specified inventory item.
1629adc4f0dbSShawn McCarney  *
1630adc4f0dbSShawn McCarney  * Searches for a JSON PowerSupply object that matches the specified inventory
1631adc4f0dbSShawn McCarney  * item.  If one is not found, a new PowerSupply object is added to the JSON
1632adc4f0dbSShawn McCarney  * array.
1633adc4f0dbSShawn McCarney  *
1634adc4f0dbSShawn McCarney  * Multiple sensors are often associated with one power supply inventory item.
1635adc4f0dbSShawn McCarney  * As a result, multiple sensor values are stored in one JSON PowerSupply
1636adc4f0dbSShawn McCarney  * object.
1637adc4f0dbSShawn McCarney  *
1638adc4f0dbSShawn McCarney  * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1639adc4f0dbSShawn McCarney  * @param inventoryItem Inventory item for the power supply.
1640adc4f0dbSShawn McCarney  * @param chassisId Chassis that contains the power supply.
1641adc4f0dbSShawn McCarney  * @return JSON PowerSupply object for the specified inventory item.
1642adc4f0dbSShawn McCarney  */
1643adc4f0dbSShawn McCarney static nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
1644adc4f0dbSShawn McCarney                                       const InventoryItem& inventoryItem,
1645adc4f0dbSShawn McCarney                                       const std::string& chassisId)
1646adc4f0dbSShawn McCarney {
1647adc4f0dbSShawn McCarney     // Check if matching PowerSupply object already exists in JSON array
1648adc4f0dbSShawn McCarney     for (nlohmann::json& powerSupply : powerSupplyArray)
1649adc4f0dbSShawn McCarney     {
1650adc4f0dbSShawn McCarney         if (powerSupply["MemberId"] == inventoryItem.name)
1651adc4f0dbSShawn McCarney         {
1652adc4f0dbSShawn McCarney             return powerSupply;
1653adc4f0dbSShawn McCarney         }
1654adc4f0dbSShawn McCarney     }
1655adc4f0dbSShawn McCarney 
1656adc4f0dbSShawn McCarney     // Add new PowerSupply object to JSON array
1657adc4f0dbSShawn McCarney     powerSupplyArray.push_back({});
1658adc4f0dbSShawn McCarney     nlohmann::json& powerSupply = powerSupplyArray.back();
1659adc4f0dbSShawn McCarney     powerSupply["@odata.id"] =
1660adc4f0dbSShawn McCarney         "/redfish/v1/Chassis/" + chassisId + "/Power#/PowerSupplies/";
1661adc4f0dbSShawn McCarney     powerSupply["MemberId"] = inventoryItem.name;
1662adc4f0dbSShawn McCarney     powerSupply["Name"] = boost::replace_all_copy(inventoryItem.name, "_", " ");
1663adc4f0dbSShawn McCarney     powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1664adc4f0dbSShawn McCarney     powerSupply["Model"] = inventoryItem.model;
1665adc4f0dbSShawn McCarney     powerSupply["PartNumber"] = inventoryItem.partNumber;
1666adc4f0dbSShawn McCarney     powerSupply["SerialNumber"] = inventoryItem.serialNumber;
1667adc4f0dbSShawn McCarney     powerSupply["Status"]["State"] = getState(&inventoryItem);
1668adc4f0dbSShawn McCarney 
1669adc4f0dbSShawn McCarney     const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1670adc4f0dbSShawn McCarney     powerSupply["Status"]["Health"] = health;
1671adc4f0dbSShawn McCarney 
1672adc4f0dbSShawn McCarney     return powerSupply;
16738fb49dd6SShawn McCarney }
16748fb49dd6SShawn McCarney 
16758fb49dd6SShawn McCarney /**
1676de629b6eSShawn McCarney  * @brief Gets the values of the specified sensors.
1677de629b6eSShawn McCarney  *
1678de629b6eSShawn McCarney  * Stores the results as JSON in the SensorsAsyncResp.
1679de629b6eSShawn McCarney  *
1680de629b6eSShawn McCarney  * Gets the sensor values asynchronously.  Stores the results later when the
1681de629b6eSShawn McCarney  * information has been obtained.
1682de629b6eSShawn McCarney  *
1683adc4f0dbSShawn McCarney  * The sensorNames set contains all requested sensors for the current chassis.
1684de629b6eSShawn McCarney  *
1685de629b6eSShawn McCarney  * To minimize the number of DBus calls, the DBus method
1686de629b6eSShawn McCarney  * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1687de629b6eSShawn McCarney  * values of all sensors provided by a connection (service).
1688de629b6eSShawn McCarney  *
1689de629b6eSShawn McCarney  * The connections set contains all the connections that provide sensor values.
1690de629b6eSShawn McCarney  *
1691de629b6eSShawn McCarney  * The objectMgrPaths map contains mappings from a connection name to the
1692de629b6eSShawn McCarney  * corresponding DBus object path that implements ObjectManager.
1693de629b6eSShawn McCarney  *
1694adc4f0dbSShawn McCarney  * The InventoryItem vector contains D-Bus inventory items associated with the
1695adc4f0dbSShawn McCarney  * sensors.  Inventory item data is needed for some Redfish sensor properties.
1696adc4f0dbSShawn McCarney  *
1697de629b6eSShawn McCarney  * @param SensorsAsyncResp Pointer to object holding response data.
1698adc4f0dbSShawn McCarney  * @param sensorNames All requested sensors within the current chassis.
1699de629b6eSShawn McCarney  * @param connections Connections that provide sensor values.
1700de629b6eSShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
1701de629b6eSShawn McCarney  * implements ObjectManager.
1702adc4f0dbSShawn McCarney  * @param inventoryItems Inventory items associated with the sensors.
1703de629b6eSShawn McCarney  */
1704de629b6eSShawn McCarney void getSensorData(
1705de629b6eSShawn McCarney     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
170649c53ac9SJohnathan Mantey     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
1707de629b6eSShawn McCarney     const boost::container::flat_set<std::string>& connections,
17088fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1709adc4f0dbSShawn McCarney         objectMgrPaths,
1710adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1711de629b6eSShawn McCarney {
1712de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getSensorData enter";
1713de629b6eSShawn McCarney     // Get managed objects from all services exposing sensors
1714de629b6eSShawn McCarney     for (const std::string& connection : connections)
1715de629b6eSShawn McCarney     {
1716de629b6eSShawn McCarney         // Response handler to process managed objects
17178fb49dd6SShawn McCarney         auto getManagedObjectsCb = [SensorsAsyncResp, sensorNames,
1718adc4f0dbSShawn McCarney                                     inventoryItems](
1719de629b6eSShawn McCarney                                        const boost::system::error_code ec,
1720de629b6eSShawn McCarney                                        ManagedObjectsVectorType& resp) {
1721de629b6eSShawn McCarney             BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
1722de629b6eSShawn McCarney             if (ec)
1723de629b6eSShawn McCarney             {
1724de629b6eSShawn McCarney                 BMCWEB_LOG_ERROR << "getManagedObjectsCb DBUS error: " << ec;
1725de629b6eSShawn McCarney                 messages::internalError(SensorsAsyncResp->res);
1726de629b6eSShawn McCarney                 return;
1727de629b6eSShawn McCarney             }
1728de629b6eSShawn McCarney             // Go through all objects and update response with sensor data
1729de629b6eSShawn McCarney             for (const auto& objDictEntry : resp)
1730de629b6eSShawn McCarney             {
1731de629b6eSShawn McCarney                 const std::string& objPath =
1732de629b6eSShawn McCarney                     static_cast<const std::string&>(objDictEntry.first);
1733de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "getManagedObjectsCb parsing object "
1734de629b6eSShawn McCarney                                  << objPath;
1735de629b6eSShawn McCarney 
1736de629b6eSShawn McCarney                 std::vector<std::string> split;
1737de629b6eSShawn McCarney                 // Reserve space for
1738de629b6eSShawn McCarney                 // /xyz/openbmc_project/sensors/<name>/<subname>
1739de629b6eSShawn McCarney                 split.reserve(6);
1740de629b6eSShawn McCarney                 boost::algorithm::split(split, objPath, boost::is_any_of("/"));
1741de629b6eSShawn McCarney                 if (split.size() < 6)
1742de629b6eSShawn McCarney                 {
1743de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << "Got path that isn't long enough "
1744de629b6eSShawn McCarney                                      << objPath;
1745de629b6eSShawn McCarney                     continue;
1746de629b6eSShawn McCarney                 }
1747de629b6eSShawn McCarney                 // These indexes aren't intuitive, as boost::split puts an empty
1748de629b6eSShawn McCarney                 // string at the beginning
1749de629b6eSShawn McCarney                 const std::string& sensorType = split[4];
1750de629b6eSShawn McCarney                 const std::string& sensorName = split[5];
1751de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "sensorName " << sensorName
1752de629b6eSShawn McCarney                                  << " sensorType " << sensorType;
175349c53ac9SJohnathan Mantey                 if (sensorNames->find(objPath) == sensorNames->end())
1754de629b6eSShawn McCarney                 {
1755de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << sensorName << " not in sensor list ";
1756de629b6eSShawn McCarney                     continue;
1757de629b6eSShawn McCarney                 }
1758de629b6eSShawn McCarney 
1759adc4f0dbSShawn McCarney                 // Find inventory item (if any) associated with sensor
1760adc4f0dbSShawn McCarney                 InventoryItem* inventoryItem =
1761adc4f0dbSShawn McCarney                     findInventoryItemForSensor(inventoryItems, objPath);
1762adc4f0dbSShawn McCarney 
1763*95a3ecadSAnthony Wilson                 const std::string& sensorSchema =
1764*95a3ecadSAnthony Wilson                     SensorsAsyncResp->chassisSubNode;
1765*95a3ecadSAnthony Wilson 
1766*95a3ecadSAnthony Wilson                 nlohmann::json* sensorJson = nullptr;
1767*95a3ecadSAnthony Wilson 
1768*95a3ecadSAnthony Wilson                 if (sensorSchema == "Sensors")
1769*95a3ecadSAnthony Wilson                 {
1770*95a3ecadSAnthony Wilson                     SensorsAsyncResp->res.jsonValue["@odata.id"] =
1771*95a3ecadSAnthony Wilson                         "/redfish/v1/Chassis/" + SensorsAsyncResp->chassisId +
1772*95a3ecadSAnthony Wilson                         "/" + SensorsAsyncResp->chassisSubNode + "/" +
1773*95a3ecadSAnthony Wilson                         sensorName;
1774*95a3ecadSAnthony Wilson                     sensorJson = &(SensorsAsyncResp->res.jsonValue);
1775*95a3ecadSAnthony Wilson                 }
1776*95a3ecadSAnthony Wilson                 else
1777*95a3ecadSAnthony Wilson                 {
1778de629b6eSShawn McCarney                     const char* fieldName = nullptr;
1779de629b6eSShawn McCarney                     if (sensorType == "temperature")
1780de629b6eSShawn McCarney                     {
1781de629b6eSShawn McCarney                         fieldName = "Temperatures";
1782de629b6eSShawn McCarney                     }
1783de629b6eSShawn McCarney                     else if (sensorType == "fan" || sensorType == "fan_tach" ||
1784de629b6eSShawn McCarney                              sensorType == "fan_pwm")
1785de629b6eSShawn McCarney                     {
1786de629b6eSShawn McCarney                         fieldName = "Fans";
1787de629b6eSShawn McCarney                     }
1788de629b6eSShawn McCarney                     else if (sensorType == "voltage")
1789de629b6eSShawn McCarney                     {
1790de629b6eSShawn McCarney                         fieldName = "Voltages";
1791de629b6eSShawn McCarney                     }
1792de629b6eSShawn McCarney                     else if (sensorType == "power")
1793de629b6eSShawn McCarney                     {
1794028f7ebcSEddie James                         if (!sensorName.compare("total_power"))
1795028f7ebcSEddie James                         {
1796028f7ebcSEddie James                             fieldName = "PowerControl";
1797028f7ebcSEddie James                         }
1798adc4f0dbSShawn McCarney                         else if ((inventoryItem != nullptr) &&
1799adc4f0dbSShawn McCarney                                  (inventoryItem->isPowerSupply))
1800028f7ebcSEddie James                         {
1801de629b6eSShawn McCarney                             fieldName = "PowerSupplies";
1802de629b6eSShawn McCarney                         }
1803adc4f0dbSShawn McCarney                         else
1804adc4f0dbSShawn McCarney                         {
1805adc4f0dbSShawn McCarney                             // Other power sensors are in SensorCollection
1806adc4f0dbSShawn McCarney                             continue;
1807adc4f0dbSShawn McCarney                         }
1808028f7ebcSEddie James                     }
1809de629b6eSShawn McCarney                     else
1810de629b6eSShawn McCarney                     {
1811de629b6eSShawn McCarney                         BMCWEB_LOG_ERROR << "Unsure how to handle sensorType "
1812de629b6eSShawn McCarney                                          << sensorType;
1813de629b6eSShawn McCarney                         continue;
1814de629b6eSShawn McCarney                     }
1815de629b6eSShawn McCarney 
1816de629b6eSShawn McCarney                     nlohmann::json& tempArray =
1817de629b6eSShawn McCarney                         SensorsAsyncResp->res.jsonValue[fieldName];
1818adc4f0dbSShawn McCarney                     if (fieldName == "PowerControl")
181949c53ac9SJohnathan Mantey                     {
1820adc4f0dbSShawn McCarney                         if (tempArray.empty())
18217ab06f49SGunnar Mills                         {
1822*95a3ecadSAnthony Wilson                             // Put multiple "sensors" into a single
1823*95a3ecadSAnthony Wilson                             // PowerControl. Follows MemberId naming and
1824*95a3ecadSAnthony Wilson                             // naming in power.hpp.
18257ab06f49SGunnar Mills                             tempArray.push_back(
1826adc4f0dbSShawn McCarney                                 {{"@odata.id",
1827adc4f0dbSShawn McCarney                                   "/redfish/v1/Chassis/" +
18287ab06f49SGunnar Mills                                       SensorsAsyncResp->chassisId + "/" +
1829adc4f0dbSShawn McCarney                                       SensorsAsyncResp->chassisSubNode + "#/" +
1830adc4f0dbSShawn McCarney                                       fieldName + "/0"}});
1831adc4f0dbSShawn McCarney                         }
1832adc4f0dbSShawn McCarney                         sensorJson = &(tempArray.back());
1833adc4f0dbSShawn McCarney                     }
1834adc4f0dbSShawn McCarney                     else if (fieldName == "PowerSupplies")
1835adc4f0dbSShawn McCarney                     {
1836adc4f0dbSShawn McCarney                         if (inventoryItem != nullptr)
1837adc4f0dbSShawn McCarney                         {
1838adc4f0dbSShawn McCarney                             sensorJson =
1839adc4f0dbSShawn McCarney                                 &(getPowerSupply(tempArray, *inventoryItem,
1840adc4f0dbSShawn McCarney                                                  SensorsAsyncResp->chassisId));
1841adc4f0dbSShawn McCarney                         }
184249c53ac9SJohnathan Mantey                     }
184349c53ac9SJohnathan Mantey                     else
184449c53ac9SJohnathan Mantey                     {
1845de629b6eSShawn McCarney                         tempArray.push_back(
1846*95a3ecadSAnthony Wilson                             {{"@odata.id",
1847*95a3ecadSAnthony Wilson                               "/redfish/v1/Chassis/" +
184849c53ac9SJohnathan Mantey                                   SensorsAsyncResp->chassisId + "/" +
1849*95a3ecadSAnthony Wilson                                   SensorsAsyncResp->chassisSubNode + "#/" +
1850*95a3ecadSAnthony Wilson                                   fieldName + "/"}});
1851adc4f0dbSShawn McCarney                         sensorJson = &(tempArray.back());
185249c53ac9SJohnathan Mantey                     }
1853*95a3ecadSAnthony Wilson                 }
1854de629b6eSShawn McCarney 
1855adc4f0dbSShawn McCarney                 if (sensorJson != nullptr)
1856adc4f0dbSShawn McCarney                 {
1857de629b6eSShawn McCarney                     objectInterfacesToJson(sensorName, sensorType,
1858*95a3ecadSAnthony Wilson                                            SensorsAsyncResp->chassisSubNode,
1859adc4f0dbSShawn McCarney                                            objDictEntry.second, *sensorJson,
1860adc4f0dbSShawn McCarney                                            inventoryItem);
1861adc4f0dbSShawn McCarney                 }
1862de629b6eSShawn McCarney             }
186349c53ac9SJohnathan Mantey             if (SensorsAsyncResp.use_count() == 1)
186449c53ac9SJohnathan Mantey             {
186549c53ac9SJohnathan Mantey                 sortJSONResponse(SensorsAsyncResp);
186649c53ac9SJohnathan Mantey                 if (SensorsAsyncResp->chassisSubNode == "Thermal")
18678bd25ccdSJames Feist                 {
18688bd25ccdSJames Feist                     populateFanRedundancy(SensorsAsyncResp);
18698bd25ccdSJames Feist                 }
187049c53ac9SJohnathan Mantey             }
1871de629b6eSShawn McCarney             BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
1872de629b6eSShawn McCarney         };
1873de629b6eSShawn McCarney 
1874de629b6eSShawn McCarney         // Find DBus object path that implements ObjectManager for the current
1875de629b6eSShawn McCarney         // connection.  If no mapping found, default to "/".
18768fb49dd6SShawn McCarney         auto iter = objectMgrPaths->find(connection);
1877de629b6eSShawn McCarney         const std::string& objectMgrPath =
18788fb49dd6SShawn McCarney             (iter != objectMgrPaths->end()) ? iter->second : "/";
1879de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
1880de629b6eSShawn McCarney                          << objectMgrPath;
1881de629b6eSShawn McCarney 
1882de629b6eSShawn McCarney         crow::connections::systemBus->async_method_call(
1883de629b6eSShawn McCarney             getManagedObjectsCb, connection, objectMgrPath,
1884de629b6eSShawn McCarney             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1885de629b6eSShawn McCarney     };
1886de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getSensorData exit";
1887de629b6eSShawn McCarney }
1888de629b6eSShawn McCarney 
1889*95a3ecadSAnthony Wilson void processSensorList(
1890*95a3ecadSAnthony Wilson     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
1891*95a3ecadSAnthony Wilson     std::shared_ptr<boost::container::flat_set<std::string>> sensorNames)
18921abe55efSEd Tanous {
1893*95a3ecadSAnthony Wilson     auto getConnectionCb =
1894*95a3ecadSAnthony Wilson         [SensorsAsyncResp, sensorNames](
1895*95a3ecadSAnthony Wilson             const boost::container::flat_set<std::string>& connections) {
189655c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "getConnectionCb enter";
1897de629b6eSShawn McCarney             auto getObjectManagerPathsCb =
189849c53ac9SJohnathan Mantey                 [SensorsAsyncResp, sensorNames, connections](
1899*95a3ecadSAnthony Wilson                     std::shared_ptr<
1900*95a3ecadSAnthony Wilson                         boost::container::flat_map<std::string, std::string>>
19018fb49dd6SShawn McCarney                         objectMgrPaths) {
1902de629b6eSShawn McCarney                     BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb enter";
1903adc4f0dbSShawn McCarney                     auto getInventoryItemsCb =
1904adc4f0dbSShawn McCarney                         [SensorsAsyncResp, sensorNames, connections,
1905adc4f0dbSShawn McCarney                          objectMgrPaths](
1906adc4f0dbSShawn McCarney                             std::shared_ptr<std::vector<InventoryItem>>
1907adc4f0dbSShawn McCarney                                 inventoryItems) {
1908adc4f0dbSShawn McCarney                             BMCWEB_LOG_DEBUG << "getInventoryItemsCb enter";
190949c53ac9SJohnathan Mantey                             // Get sensor data and store results in JSON
1910de629b6eSShawn McCarney                             getSensorData(SensorsAsyncResp, sensorNames,
1911adc4f0dbSShawn McCarney                                           connections, objectMgrPaths,
1912adc4f0dbSShawn McCarney                                           inventoryItems);
1913adc4f0dbSShawn McCarney                             BMCWEB_LOG_DEBUG << "getInventoryItemsCb exit";
1914adc4f0dbSShawn McCarney                         };
1915adc4f0dbSShawn McCarney 
1916adc4f0dbSShawn McCarney                     // Get inventory items associated with sensors
1917adc4f0dbSShawn McCarney                     getInventoryItems(SensorsAsyncResp, sensorNames,
1918adc4f0dbSShawn McCarney                                       objectMgrPaths,
1919adc4f0dbSShawn McCarney                                       std::move(getInventoryItemsCb));
1920adc4f0dbSShawn McCarney 
1921de629b6eSShawn McCarney                     BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb exit";
192208777fb0SLewanczyk, Dawid                 };
1923de629b6eSShawn McCarney 
192449c53ac9SJohnathan Mantey             // Get mapping from connection names to the DBus object
192549c53ac9SJohnathan Mantey             // paths that implement the ObjectManager interface
1926de629b6eSShawn McCarney             getObjectManagerPaths(SensorsAsyncResp,
1927de629b6eSShawn McCarney                                   std::move(getObjectManagerPathsCb));
192855c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "getConnectionCb exit";
192908777fb0SLewanczyk, Dawid         };
1930de629b6eSShawn McCarney 
1931de629b6eSShawn McCarney     // Get set of connections that provide sensor values
1932*95a3ecadSAnthony Wilson     getConnections(SensorsAsyncResp, sensorNames, std::move(getConnectionCb));
1933*95a3ecadSAnthony Wilson }
1934*95a3ecadSAnthony Wilson 
1935*95a3ecadSAnthony Wilson /**
1936*95a3ecadSAnthony Wilson  * @brief Entry point for retrieving sensors data related to requested
1937*95a3ecadSAnthony Wilson  *        chassis.
1938*95a3ecadSAnthony Wilson  * @param SensorsAsyncResp   Pointer to object holding response data
1939*95a3ecadSAnthony Wilson  */
1940*95a3ecadSAnthony Wilson void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
1941*95a3ecadSAnthony Wilson {
1942*95a3ecadSAnthony Wilson     BMCWEB_LOG_DEBUG << "getChassisData enter";
1943*95a3ecadSAnthony Wilson     auto getChassisCb =
1944*95a3ecadSAnthony Wilson         [SensorsAsyncResp](
1945*95a3ecadSAnthony Wilson             std::shared_ptr<boost::container::flat_set<std::string>>
1946*95a3ecadSAnthony Wilson                 sensorNames) {
1947*95a3ecadSAnthony Wilson             BMCWEB_LOG_DEBUG << "getChassisCb enter";
1948*95a3ecadSAnthony Wilson             processSensorList(SensorsAsyncResp, sensorNames);
194955c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "getChassisCb exit";
195008777fb0SLewanczyk, Dawid         };
19514f9a2130SJennifer Lee     SensorsAsyncResp->res.jsonValue["Redundancy"] = nlohmann::json::array();
195208777fb0SLewanczyk, Dawid 
195326f03899SShawn McCarney     // Get set of sensors in chassis
1954588c3f0dSKowalski, Kamil     getChassis(SensorsAsyncResp, std::move(getChassisCb));
195555c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisData exit";
195608777fb0SLewanczyk, Dawid };
195708777fb0SLewanczyk, Dawid 
1958413961deSRichard Marian Thomaiyar /**
195949c53ac9SJohnathan Mantey  * @brief Find the requested sensorName in the list of all sensors supplied by
196049c53ac9SJohnathan Mantey  * the chassis node
196149c53ac9SJohnathan Mantey  *
196249c53ac9SJohnathan Mantey  * @param sensorName   The sensor name supplied in the PATCH request
196349c53ac9SJohnathan Mantey  * @param sensorsList  The list of sensors managed by the chassis node
196449c53ac9SJohnathan Mantey  * @param sensorsModified  The list of sensors that were found as a result of
196549c53ac9SJohnathan Mantey  *                         repeated calls to this function
196649c53ac9SJohnathan Mantey  */
196749c53ac9SJohnathan Mantey bool findSensorNameUsingSensorPath(
19680a86febdSRichard Marian Thomaiyar     std::string_view sensorName,
196949c53ac9SJohnathan Mantey     boost::container::flat_set<std::string>& sensorsList,
197049c53ac9SJohnathan Mantey     boost::container::flat_set<std::string>& sensorsModified)
197149c53ac9SJohnathan Mantey {
19720a86febdSRichard Marian Thomaiyar     for (std::string_view chassisSensor : sensorsList)
197349c53ac9SJohnathan Mantey     {
19740a86febdSRichard Marian Thomaiyar         std::size_t pos = chassisSensor.rfind("/");
19750a86febdSRichard Marian Thomaiyar         if (pos >= (chassisSensor.size() - 1))
197649c53ac9SJohnathan Mantey         {
197749c53ac9SJohnathan Mantey             continue;
197849c53ac9SJohnathan Mantey         }
19790a86febdSRichard Marian Thomaiyar         std::string_view thisSensorName = chassisSensor.substr(pos + 1);
198049c53ac9SJohnathan Mantey         if (thisSensorName == sensorName)
198149c53ac9SJohnathan Mantey         {
198249c53ac9SJohnathan Mantey             sensorsModified.emplace(chassisSensor);
198349c53ac9SJohnathan Mantey             return true;
198449c53ac9SJohnathan Mantey         }
198549c53ac9SJohnathan Mantey     }
198649c53ac9SJohnathan Mantey     return false;
198749c53ac9SJohnathan Mantey }
198849c53ac9SJohnathan Mantey 
198949c53ac9SJohnathan Mantey /**
1990413961deSRichard Marian Thomaiyar  * @brief Entry point for overriding sensor values of given sensor
1991413961deSRichard Marian Thomaiyar  *
1992413961deSRichard Marian Thomaiyar  * @param res   response object
1993413961deSRichard Marian Thomaiyar  * @param req   request object
1994413961deSRichard Marian Thomaiyar  * @param params   parameter passed for CRUD
1995413961deSRichard Marian Thomaiyar  * @param typeList   TypeList of sensors for the resource queried
1996413961deSRichard Marian Thomaiyar  * @param chassisSubNode   Chassis Node for which the query has to happen
1997413961deSRichard Marian Thomaiyar  */
1998413961deSRichard Marian Thomaiyar void setSensorOverride(crow::Response& res, const crow::Request& req,
1999413961deSRichard Marian Thomaiyar                        const std::vector<std::string>& params,
200085e1424fSEd Tanous                        const std::vector<const char*> typeList,
2001413961deSRichard Marian Thomaiyar                        const std::string& chassisSubNode)
2002413961deSRichard Marian Thomaiyar {
2003413961deSRichard Marian Thomaiyar 
2004413961deSRichard Marian Thomaiyar     // TODO: Need to figure out dynamic way to restrict patch (Set Sensor
2005413961deSRichard Marian Thomaiyar     // override) based on another d-bus announcement to be more generic.
2006413961deSRichard Marian Thomaiyar     if (params.size() != 1)
2007413961deSRichard Marian Thomaiyar     {
2008413961deSRichard Marian Thomaiyar         messages::internalError(res);
2009413961deSRichard Marian Thomaiyar         res.end();
2010413961deSRichard Marian Thomaiyar         return;
2011413961deSRichard Marian Thomaiyar     }
2012f65af9e8SRichard Marian Thomaiyar 
2013f65af9e8SRichard Marian Thomaiyar     std::unordered_map<std::string, std::vector<nlohmann::json>> allCollections;
2014f65af9e8SRichard Marian Thomaiyar     std::optional<std::vector<nlohmann::json>> temperatureCollections;
2015f65af9e8SRichard Marian Thomaiyar     std::optional<std::vector<nlohmann::json>> fanCollections;
2016f65af9e8SRichard Marian Thomaiyar     std::vector<nlohmann::json> voltageCollections;
2017f65af9e8SRichard Marian Thomaiyar     BMCWEB_LOG_INFO << "setSensorOverride for subNode" << chassisSubNode
2018f65af9e8SRichard Marian Thomaiyar                     << "\n";
2019f65af9e8SRichard Marian Thomaiyar 
2020413961deSRichard Marian Thomaiyar     if (chassisSubNode == "Thermal")
2021413961deSRichard Marian Thomaiyar     {
2022f65af9e8SRichard Marian Thomaiyar         if (!json_util::readJson(req, res, "Temperatures",
2023f65af9e8SRichard Marian Thomaiyar                                  temperatureCollections, "Fans",
2024f65af9e8SRichard Marian Thomaiyar                                  fanCollections))
2025f65af9e8SRichard Marian Thomaiyar         {
2026f65af9e8SRichard Marian Thomaiyar             return;
2027f65af9e8SRichard Marian Thomaiyar         }
2028f65af9e8SRichard Marian Thomaiyar         if (!temperatureCollections && !fanCollections)
2029f65af9e8SRichard Marian Thomaiyar         {
2030f65af9e8SRichard Marian Thomaiyar             messages::resourceNotFound(res, "Thermal",
2031f65af9e8SRichard Marian Thomaiyar                                        "Temperatures / Voltages");
2032f65af9e8SRichard Marian Thomaiyar             res.end();
2033f65af9e8SRichard Marian Thomaiyar             return;
2034f65af9e8SRichard Marian Thomaiyar         }
2035f65af9e8SRichard Marian Thomaiyar         if (temperatureCollections)
2036f65af9e8SRichard Marian Thomaiyar         {
2037f65af9e8SRichard Marian Thomaiyar             allCollections.emplace("Temperatures",
2038f65af9e8SRichard Marian Thomaiyar                                    *std::move(temperatureCollections));
2039f65af9e8SRichard Marian Thomaiyar         }
2040f65af9e8SRichard Marian Thomaiyar         if (fanCollections)
2041f65af9e8SRichard Marian Thomaiyar         {
2042f65af9e8SRichard Marian Thomaiyar             allCollections.emplace("Fans", *std::move(fanCollections));
2043f65af9e8SRichard Marian Thomaiyar         }
2044413961deSRichard Marian Thomaiyar     }
2045413961deSRichard Marian Thomaiyar     else if (chassisSubNode == "Power")
2046413961deSRichard Marian Thomaiyar     {
2047f65af9e8SRichard Marian Thomaiyar         if (!json_util::readJson(req, res, "Voltages", voltageCollections))
2048f65af9e8SRichard Marian Thomaiyar         {
2049f65af9e8SRichard Marian Thomaiyar             return;
2050f65af9e8SRichard Marian Thomaiyar         }
2051f65af9e8SRichard Marian Thomaiyar         allCollections.emplace("Voltages", std::move(voltageCollections));
2052413961deSRichard Marian Thomaiyar     }
2053413961deSRichard Marian Thomaiyar     else
2054413961deSRichard Marian Thomaiyar     {
2055413961deSRichard Marian Thomaiyar         res.result(boost::beast::http::status::not_found);
2056413961deSRichard Marian Thomaiyar         res.end();
2057413961deSRichard Marian Thomaiyar         return;
2058413961deSRichard Marian Thomaiyar     }
2059413961deSRichard Marian Thomaiyar 
2060f65af9e8SRichard Marian Thomaiyar     const char* propertyValueName;
2061f65af9e8SRichard Marian Thomaiyar     std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
2062413961deSRichard Marian Thomaiyar     std::string memberId;
2063413961deSRichard Marian Thomaiyar     double value;
2064f65af9e8SRichard Marian Thomaiyar     for (auto& collectionItems : allCollections)
2065f65af9e8SRichard Marian Thomaiyar     {
2066f65af9e8SRichard Marian Thomaiyar         if (collectionItems.first == "Temperatures")
2067f65af9e8SRichard Marian Thomaiyar         {
2068f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingCelsius";
2069f65af9e8SRichard Marian Thomaiyar         }
2070f65af9e8SRichard Marian Thomaiyar         else if (collectionItems.first == "Fans")
2071f65af9e8SRichard Marian Thomaiyar         {
2072f65af9e8SRichard Marian Thomaiyar             propertyValueName = "Reading";
2073f65af9e8SRichard Marian Thomaiyar         }
2074f65af9e8SRichard Marian Thomaiyar         else
2075f65af9e8SRichard Marian Thomaiyar         {
2076f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingVolts";
2077f65af9e8SRichard Marian Thomaiyar         }
2078f65af9e8SRichard Marian Thomaiyar         for (auto& item : collectionItems.second)
2079f65af9e8SRichard Marian Thomaiyar         {
2080f65af9e8SRichard Marian Thomaiyar             if (!json_util::readJson(item, res, "MemberId", memberId,
2081413961deSRichard Marian Thomaiyar                                      propertyValueName, value))
2082413961deSRichard Marian Thomaiyar             {
2083413961deSRichard Marian Thomaiyar                 return;
2084413961deSRichard Marian Thomaiyar             }
2085f65af9e8SRichard Marian Thomaiyar             overrideMap.emplace(memberId,
2086f65af9e8SRichard Marian Thomaiyar                                 std::make_pair(value, collectionItems.first));
2087f65af9e8SRichard Marian Thomaiyar         }
2088f65af9e8SRichard Marian Thomaiyar     }
2089413961deSRichard Marian Thomaiyar     const std::string& chassisName = params[0];
2090413961deSRichard Marian Thomaiyar     auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
2091413961deSRichard Marian Thomaiyar         res, chassisName, typeList, chassisSubNode);
209249c53ac9SJohnathan Mantey     auto getChassisSensorListCb = [sensorAsyncResp,
209349c53ac9SJohnathan Mantey                                    overrideMap](const std::shared_ptr<
209449c53ac9SJohnathan Mantey                                                 boost::container::flat_set<
209549c53ac9SJohnathan Mantey                                                     std::string>>
209649c53ac9SJohnathan Mantey                                                     sensorsList) {
209749c53ac9SJohnathan Mantey         // Match sensor names in the PATCH request to those managed by the
209849c53ac9SJohnathan Mantey         // chassis node
209949c53ac9SJohnathan Mantey         const std::shared_ptr<boost::container::flat_set<std::string>>
210049c53ac9SJohnathan Mantey             sensorNames =
210149c53ac9SJohnathan Mantey                 std::make_shared<boost::container::flat_set<std::string>>();
2102f65af9e8SRichard Marian Thomaiyar         for (const auto& item : overrideMap)
2103413961deSRichard Marian Thomaiyar         {
2104f65af9e8SRichard Marian Thomaiyar             const auto& sensor = item.first;
210549c53ac9SJohnathan Mantey             if (!findSensorNameUsingSensorPath(sensor, *sensorsList,
210649c53ac9SJohnathan Mantey                                                *sensorNames))
2107f65af9e8SRichard Marian Thomaiyar             {
2108f65af9e8SRichard Marian Thomaiyar                 BMCWEB_LOG_INFO << "Unable to find memberId " << item.first;
2109413961deSRichard Marian Thomaiyar                 messages::resourceNotFound(sensorAsyncResp->res,
2110f65af9e8SRichard Marian Thomaiyar                                            item.second.second, item.first);
2111413961deSRichard Marian Thomaiyar                 return;
2112413961deSRichard Marian Thomaiyar             }
2113f65af9e8SRichard Marian Thomaiyar         }
2114413961deSRichard Marian Thomaiyar         // Get the connection to which the memberId belongs
2115413961deSRichard Marian Thomaiyar         auto getObjectsWithConnectionCb =
2116f65af9e8SRichard Marian Thomaiyar             [sensorAsyncResp, overrideMap](
2117413961deSRichard Marian Thomaiyar                 const boost::container::flat_set<std::string>& connections,
2118413961deSRichard Marian Thomaiyar                 const std::set<std::pair<std::string, std::string>>&
2119413961deSRichard Marian Thomaiyar                     objectsWithConnection) {
2120f65af9e8SRichard Marian Thomaiyar                 if (objectsWithConnection.size() != overrideMap.size())
2121413961deSRichard Marian Thomaiyar                 {
2122413961deSRichard Marian Thomaiyar                     BMCWEB_LOG_INFO
2123f65af9e8SRichard Marian Thomaiyar                         << "Unable to find all objects with proper connection "
2124f65af9e8SRichard Marian Thomaiyar                         << objectsWithConnection.size() << " requested "
2125f65af9e8SRichard Marian Thomaiyar                         << overrideMap.size() << "\n";
2126413961deSRichard Marian Thomaiyar                     messages::resourceNotFound(
2127413961deSRichard Marian Thomaiyar                         sensorAsyncResp->res,
2128413961deSRichard Marian Thomaiyar                         sensorAsyncResp->chassisSubNode == "Thermal"
2129413961deSRichard Marian Thomaiyar                             ? "Temperatures"
2130413961deSRichard Marian Thomaiyar                             : "Voltages",
2131f65af9e8SRichard Marian Thomaiyar                         "Count");
2132f65af9e8SRichard Marian Thomaiyar                     return;
2133f65af9e8SRichard Marian Thomaiyar                 }
2134f65af9e8SRichard Marian Thomaiyar                 for (const auto& item : objectsWithConnection)
2135f65af9e8SRichard Marian Thomaiyar                 {
2136f65af9e8SRichard Marian Thomaiyar 
2137f65af9e8SRichard Marian Thomaiyar                     auto lastPos = item.first.rfind('/');
2138f65af9e8SRichard Marian Thomaiyar                     if (lastPos == std::string::npos)
2139f65af9e8SRichard Marian Thomaiyar                     {
2140f65af9e8SRichard Marian Thomaiyar                         messages::internalError(sensorAsyncResp->res);
2141f65af9e8SRichard Marian Thomaiyar                         return;
2142f65af9e8SRichard Marian Thomaiyar                     }
2143f65af9e8SRichard Marian Thomaiyar                     std::string sensorName = item.first.substr(lastPos + 1);
2144f65af9e8SRichard Marian Thomaiyar 
2145f65af9e8SRichard Marian Thomaiyar                     const auto& iterator = overrideMap.find(sensorName);
2146f65af9e8SRichard Marian Thomaiyar                     if (iterator == overrideMap.end())
2147f65af9e8SRichard Marian Thomaiyar                     {
2148f65af9e8SRichard Marian Thomaiyar                         BMCWEB_LOG_INFO << "Unable to find sensor object"
2149f65af9e8SRichard Marian Thomaiyar                                         << item.first << "\n";
2150f65af9e8SRichard Marian Thomaiyar                         messages::internalError(sensorAsyncResp->res);
2151413961deSRichard Marian Thomaiyar                         return;
2152413961deSRichard Marian Thomaiyar                     }
2153413961deSRichard Marian Thomaiyar                     crow::connections::systemBus->async_method_call(
2154f65af9e8SRichard Marian Thomaiyar                         [sensorAsyncResp](const boost::system::error_code ec) {
2155413961deSRichard Marian Thomaiyar                             if (ec)
2156413961deSRichard Marian Thomaiyar                             {
2157413961deSRichard Marian Thomaiyar                                 BMCWEB_LOG_DEBUG
2158f65af9e8SRichard Marian Thomaiyar                                     << "setOverrideValueStatus DBUS error: "
2159413961deSRichard Marian Thomaiyar                                     << ec;
2160413961deSRichard Marian Thomaiyar                                 messages::internalError(sensorAsyncResp->res);
2161413961deSRichard Marian Thomaiyar                                 return;
2162413961deSRichard Marian Thomaiyar                             }
2163413961deSRichard Marian Thomaiyar                         },
2164f65af9e8SRichard Marian Thomaiyar                         item.second, item.first,
2165413961deSRichard Marian Thomaiyar                         "org.freedesktop.DBus.Properties", "Set",
2166413961deSRichard Marian Thomaiyar                         "xyz.openbmc_project.Sensor.Value", "Value",
2167f65af9e8SRichard Marian Thomaiyar                         sdbusplus::message::variant<double>(
2168f65af9e8SRichard Marian Thomaiyar                             iterator->second.first));
2169f65af9e8SRichard Marian Thomaiyar                 }
2170413961deSRichard Marian Thomaiyar             };
2171413961deSRichard Marian Thomaiyar         // Get object with connection for the given sensor name
2172413961deSRichard Marian Thomaiyar         getObjectsWithConnection(sensorAsyncResp, sensorNames,
2173413961deSRichard Marian Thomaiyar                                  std::move(getObjectsWithConnectionCb));
2174413961deSRichard Marian Thomaiyar     };
2175413961deSRichard Marian Thomaiyar     // get full sensor list for the given chassisId and cross verify the sensor.
2176413961deSRichard Marian Thomaiyar     getChassis(sensorAsyncResp, std::move(getChassisSensorListCb));
2177413961deSRichard Marian Thomaiyar }
2178413961deSRichard Marian Thomaiyar 
2179*95a3ecadSAnthony Wilson class SensorCollection : public Node
2180*95a3ecadSAnthony Wilson {
2181*95a3ecadSAnthony Wilson   public:
2182*95a3ecadSAnthony Wilson     SensorCollection(CrowApp& app) :
2183*95a3ecadSAnthony Wilson         Node(app, "/redfish/v1/Chassis/<str>/Sensors", std::string())
2184*95a3ecadSAnthony Wilson     {
2185*95a3ecadSAnthony Wilson         entityPrivileges = {
2186*95a3ecadSAnthony Wilson             {boost::beast::http::verb::get, {{"Login"}}},
2187*95a3ecadSAnthony Wilson             {boost::beast::http::verb::head, {{"Login"}}},
2188*95a3ecadSAnthony Wilson             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2189*95a3ecadSAnthony Wilson             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2190*95a3ecadSAnthony Wilson             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2191*95a3ecadSAnthony Wilson             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2192*95a3ecadSAnthony Wilson     }
2193*95a3ecadSAnthony Wilson 
2194*95a3ecadSAnthony Wilson   private:
2195*95a3ecadSAnthony Wilson     std::vector<const char*> typeList = {
2196*95a3ecadSAnthony Wilson         "/xyz/openbmc_project/sensors/power",
2197*95a3ecadSAnthony Wilson         "/xyz/openbmc_project/sensors/current"};
2198*95a3ecadSAnthony Wilson     void doGet(crow::Response& res, const crow::Request& req,
2199*95a3ecadSAnthony Wilson                const std::vector<std::string>& params) override
2200*95a3ecadSAnthony Wilson     {
2201*95a3ecadSAnthony Wilson         BMCWEB_LOG_DEBUG << "SensorCollection doGet enter";
2202*95a3ecadSAnthony Wilson         if (params.size() != 1)
2203*95a3ecadSAnthony Wilson         {
2204*95a3ecadSAnthony Wilson             BMCWEB_LOG_DEBUG << "SensorCollection doGet param size < 1";
2205*95a3ecadSAnthony Wilson             messages::internalError(res);
2206*95a3ecadSAnthony Wilson             res.end();
2207*95a3ecadSAnthony Wilson             return;
2208*95a3ecadSAnthony Wilson         }
2209*95a3ecadSAnthony Wilson 
2210*95a3ecadSAnthony Wilson         const std::string& chassisId = params[0];
2211*95a3ecadSAnthony Wilson         std::shared_ptr<SensorsAsyncResp> asyncResp =
2212*95a3ecadSAnthony Wilson             std::make_shared<SensorsAsyncResp>(res, chassisId, typeList,
2213*95a3ecadSAnthony Wilson                                                "Sensors");
2214*95a3ecadSAnthony Wilson 
2215*95a3ecadSAnthony Wilson         auto getChassisCb =
2216*95a3ecadSAnthony Wilson             [asyncResp](std::shared_ptr<boost::container::flat_set<std::string>>
2217*95a3ecadSAnthony Wilson                             sensorNames) {
2218*95a3ecadSAnthony Wilson                 BMCWEB_LOG_DEBUG << "getChassisCb enter";
2219*95a3ecadSAnthony Wilson 
2220*95a3ecadSAnthony Wilson                 nlohmann::json& entriesArray =
2221*95a3ecadSAnthony Wilson                     asyncResp->res.jsonValue["Members"];
2222*95a3ecadSAnthony Wilson                 for (auto& sensor : *sensorNames)
2223*95a3ecadSAnthony Wilson                 {
2224*95a3ecadSAnthony Wilson                     BMCWEB_LOG_DEBUG << "Adding sensor: " << sensor;
2225*95a3ecadSAnthony Wilson 
2226*95a3ecadSAnthony Wilson                     std::size_t lastPos = sensor.rfind("/");
2227*95a3ecadSAnthony Wilson                     if (lastPos == std::string::npos ||
2228*95a3ecadSAnthony Wilson                         lastPos + 1 >= sensor.size())
2229*95a3ecadSAnthony Wilson                     {
2230*95a3ecadSAnthony Wilson                         BMCWEB_LOG_ERROR << "Invalid sensor path: " << sensor;
2231*95a3ecadSAnthony Wilson                         messages::internalError(asyncResp->res);
2232*95a3ecadSAnthony Wilson                         return;
2233*95a3ecadSAnthony Wilson                     }
2234*95a3ecadSAnthony Wilson                     std::string sensorName = sensor.substr(lastPos + 1);
2235*95a3ecadSAnthony Wilson                     entriesArray.push_back(
2236*95a3ecadSAnthony Wilson                         {{"@odata.id",
2237*95a3ecadSAnthony Wilson                           "/redfish/v1/Chassis/" + asyncResp->chassisId + "/" +
2238*95a3ecadSAnthony Wilson                               asyncResp->chassisSubNode + "/" + sensorName}});
2239*95a3ecadSAnthony Wilson                 }
2240*95a3ecadSAnthony Wilson 
2241*95a3ecadSAnthony Wilson                 asyncResp->res.jsonValue["Members@odata.count"] =
2242*95a3ecadSAnthony Wilson                     entriesArray.size();
2243*95a3ecadSAnthony Wilson                 BMCWEB_LOG_DEBUG << "getChassisCb exit";
2244*95a3ecadSAnthony Wilson             };
2245*95a3ecadSAnthony Wilson 
2246*95a3ecadSAnthony Wilson         // Get set of sensors in chassis
2247*95a3ecadSAnthony Wilson         getChassis(asyncResp, std::move(getChassisCb));
2248*95a3ecadSAnthony Wilson         BMCWEB_LOG_DEBUG << "SensorCollection doGet exit";
2249*95a3ecadSAnthony Wilson     }
2250*95a3ecadSAnthony Wilson };
2251*95a3ecadSAnthony Wilson 
2252*95a3ecadSAnthony Wilson class Sensor : public Node
2253*95a3ecadSAnthony Wilson {
2254*95a3ecadSAnthony Wilson   public:
2255*95a3ecadSAnthony Wilson     Sensor(CrowApp& app) :
2256*95a3ecadSAnthony Wilson         Node(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/", std::string(),
2257*95a3ecadSAnthony Wilson              std::string())
2258*95a3ecadSAnthony Wilson     {
2259*95a3ecadSAnthony Wilson         entityPrivileges = {
2260*95a3ecadSAnthony Wilson             {boost::beast::http::verb::get, {{"Login"}}},
2261*95a3ecadSAnthony Wilson             {boost::beast::http::verb::head, {{"Login"}}},
2262*95a3ecadSAnthony Wilson             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2263*95a3ecadSAnthony Wilson             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2264*95a3ecadSAnthony Wilson             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2265*95a3ecadSAnthony Wilson             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2266*95a3ecadSAnthony Wilson     }
2267*95a3ecadSAnthony Wilson 
2268*95a3ecadSAnthony Wilson   private:
2269*95a3ecadSAnthony Wilson     void doGet(crow::Response& res, const crow::Request& req,
2270*95a3ecadSAnthony Wilson                const std::vector<std::string>& params) override
2271*95a3ecadSAnthony Wilson     {
2272*95a3ecadSAnthony Wilson         BMCWEB_LOG_DEBUG << "Sensor doGet enter";
2273*95a3ecadSAnthony Wilson         if (params.size() != 2)
2274*95a3ecadSAnthony Wilson         {
2275*95a3ecadSAnthony Wilson             BMCWEB_LOG_DEBUG << "Sensor doGet param size < 2";
2276*95a3ecadSAnthony Wilson             messages::internalError(res);
2277*95a3ecadSAnthony Wilson             res.end();
2278*95a3ecadSAnthony Wilson             return;
2279*95a3ecadSAnthony Wilson         }
2280*95a3ecadSAnthony Wilson         const std::string& chassisId = params[0];
2281*95a3ecadSAnthony Wilson         std::shared_ptr<SensorsAsyncResp> asyncResp =
2282*95a3ecadSAnthony Wilson             std::make_shared<SensorsAsyncResp>(
2283*95a3ecadSAnthony Wilson                 res, chassisId, std::vector<const char*>(), "Sensors");
2284*95a3ecadSAnthony Wilson 
2285*95a3ecadSAnthony Wilson         const std::string& sensorName = params[1];
2286*95a3ecadSAnthony Wilson         const std::array<const char*, 1> interfaces = {
2287*95a3ecadSAnthony Wilson             "xyz.openbmc_project.Sensor.Value"};
2288*95a3ecadSAnthony Wilson 
2289*95a3ecadSAnthony Wilson         // Get a list of all of the sensors that implement Sensor.Value
2290*95a3ecadSAnthony Wilson         // and get the path and service name associated with the sensor
2291*95a3ecadSAnthony Wilson         crow::connections::systemBus->async_method_call(
2292*95a3ecadSAnthony Wilson             [asyncResp, sensorName](const boost::system::error_code ec,
2293*95a3ecadSAnthony Wilson                                     const GetSubTreeType& subtree) {
2294*95a3ecadSAnthony Wilson                 BMCWEB_LOG_DEBUG << "respHandler1 enter";
2295*95a3ecadSAnthony Wilson                 if (ec)
2296*95a3ecadSAnthony Wilson                 {
2297*95a3ecadSAnthony Wilson                     messages::internalError(asyncResp->res);
2298*95a3ecadSAnthony Wilson                     BMCWEB_LOG_ERROR << "Sensor getSensorPaths resp_handler: "
2299*95a3ecadSAnthony Wilson                                      << "Dbus error " << ec;
2300*95a3ecadSAnthony Wilson                     return;
2301*95a3ecadSAnthony Wilson                 }
2302*95a3ecadSAnthony Wilson 
2303*95a3ecadSAnthony Wilson                 GetSubTreeType::const_iterator it = std::find_if(
2304*95a3ecadSAnthony Wilson                     subtree.begin(), subtree.end(),
2305*95a3ecadSAnthony Wilson                     [sensorName](
2306*95a3ecadSAnthony Wilson                         const std::pair<
2307*95a3ecadSAnthony Wilson                             std::string,
2308*95a3ecadSAnthony Wilson                             std::vector<std::pair<std::string,
2309*95a3ecadSAnthony Wilson                                                   std::vector<std::string>>>>&
2310*95a3ecadSAnthony Wilson                             object) {
2311*95a3ecadSAnthony Wilson                         std::string_view sensor = object.first;
2312*95a3ecadSAnthony Wilson                         std::size_t lastPos = sensor.rfind("/");
2313*95a3ecadSAnthony Wilson                         if (lastPos == std::string::npos ||
2314*95a3ecadSAnthony Wilson                             lastPos + 1 >= sensor.size())
2315*95a3ecadSAnthony Wilson                         {
2316*95a3ecadSAnthony Wilson                             BMCWEB_LOG_ERROR << "Invalid sensor path: "
2317*95a3ecadSAnthony Wilson                                              << sensor;
2318*95a3ecadSAnthony Wilson                             return false;
2319*95a3ecadSAnthony Wilson                         }
2320*95a3ecadSAnthony Wilson                         std::string_view name = sensor.substr(lastPos + 1);
2321*95a3ecadSAnthony Wilson 
2322*95a3ecadSAnthony Wilson                         return name == sensorName;
2323*95a3ecadSAnthony Wilson                     });
2324*95a3ecadSAnthony Wilson 
2325*95a3ecadSAnthony Wilson                 if (it == subtree.end())
2326*95a3ecadSAnthony Wilson                 {
2327*95a3ecadSAnthony Wilson                     BMCWEB_LOG_ERROR << "Could not find path for sensor: "
2328*95a3ecadSAnthony Wilson                                      << sensorName;
2329*95a3ecadSAnthony Wilson                     messages::resourceNotFound(asyncResp->res, "Sensor",
2330*95a3ecadSAnthony Wilson                                                sensorName);
2331*95a3ecadSAnthony Wilson                     return;
2332*95a3ecadSAnthony Wilson                 }
2333*95a3ecadSAnthony Wilson                 std::string_view sensorPath = (*it).first;
2334*95a3ecadSAnthony Wilson                 BMCWEB_LOG_DEBUG << "Found sensor path for sensor '"
2335*95a3ecadSAnthony Wilson                                  << sensorName << "': " << sensorPath;
2336*95a3ecadSAnthony Wilson 
2337*95a3ecadSAnthony Wilson                 const std::shared_ptr<boost::container::flat_set<std::string>>
2338*95a3ecadSAnthony Wilson                     sensorList = std::make_shared<
2339*95a3ecadSAnthony Wilson                         boost::container::flat_set<std::string>>();
2340*95a3ecadSAnthony Wilson 
2341*95a3ecadSAnthony Wilson                 sensorList->emplace(sensorPath);
2342*95a3ecadSAnthony Wilson                 processSensorList(asyncResp, sensorList);
2343*95a3ecadSAnthony Wilson                 BMCWEB_LOG_DEBUG << "respHandler1 exit";
2344*95a3ecadSAnthony Wilson             },
2345*95a3ecadSAnthony Wilson             "xyz.openbmc_project.ObjectMapper",
2346*95a3ecadSAnthony Wilson             "/xyz/openbmc_project/object_mapper",
2347*95a3ecadSAnthony Wilson             "xyz.openbmc_project.ObjectMapper", "GetSubTree",
2348*95a3ecadSAnthony Wilson             "/xyz/openbmc_project/sensors", 2, interfaces);
2349*95a3ecadSAnthony Wilson     }
2350*95a3ecadSAnthony Wilson };
2351*95a3ecadSAnthony Wilson 
235208777fb0SLewanczyk, Dawid } // namespace redfish
2353