xref: /openbmc/bmcweb/features/redfish/lib/sensors.hpp (revision 271584ab78b4c1926f766aa26ddfde7da329059f)
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 
1895a3ecadSAnthony Wilson #include "node.hpp"
1995a3ecadSAnthony 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:
52*271584abSEd Tanous     SensorsAsyncResp(crow::Response& response, const std::string& chassisIdIn,
53*271584abSEd Tanous                      const std::vector<const char*> typesIn,
542474adfaSEd Tanous                      const std::string& subNode) :
5543b761d0SEd Tanous         res(response),
56*271584abSEd Tanous         chassisId(chassisIdIn), types(typesIn), 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         }
31395a3ecadSAnthony Wilson         else if (chassisSubNode == "Sensors")
31495a3ecadSAnthony Wilson         {
31595a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["@odata.type"] =
31695a3ecadSAnthony Wilson                 "#SensorCollection.SensorCollection";
31795a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["@odata.context"] =
31895a3ecadSAnthony Wilson                 "/redfish/v1/$metadata#SensorCollection.SensorCollection";
31995a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["Description"] =
32095a3ecadSAnthony Wilson                 "Collection of Sensors for this Chassis";
32195a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["Members"] =
32295a3ecadSAnthony Wilson                 nlohmann::json::array();
32395a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["Members@odata.count"] = 0;
32495a3ecadSAnthony Wilson         }
32595a3ecadSAnthony Wilson 
32695a3ecadSAnthony Wilson         if (chassisSubNode != "Sensors")
32795a3ecadSAnthony Wilson         {
32895a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["Id"] = chassisSubNode;
32995a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["@odata.context"] =
33095a3ecadSAnthony Wilson                 "/redfish/v1/$metadata#" + chassisSubNode + "." +
33195a3ecadSAnthony Wilson                 chassisSubNode;
33295a3ecadSAnthony Wilson         }
33395a3ecadSAnthony 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)}](
343*271584abSEd Tanous                 const boost::system::error_code& e,
34449c53ac9SJohnathan Mantey                 const std::variant<std::vector<std::string>>&
34549c53ac9SJohnathan Mantey                     variantEndpoints) {
346*271584abSEd Tanous                 if (e)
34749c53ac9SJohnathan Mantey                 {
348*271584abSEd Tanous                     if (e.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"
36295a3ecadSAnthony Wilson                             : sensorsAsyncResp->chassisSubNode == "Power"
36395a3ecadSAnthony Wilson                                   ? "Voltages"
36495a3ecadSAnthony 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",
384*271584abSEd Tanous         "/xyz/openbmc_project/inventory", 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",
455*271584abSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, interfaces);
456de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getObjectManagerPaths exit";
457de629b6eSShawn McCarney }
458de629b6eSShawn McCarney 
459de629b6eSShawn McCarney /**
460adc4f0dbSShawn McCarney  * @brief Returns the Redfish State value for the specified inventory item.
461adc4f0dbSShawn McCarney  * @param inventoryItem D-Bus inventory item associated with a sensor.
462adc4f0dbSShawn McCarney  * @return State value for inventory item.
46334dd179eSJames Feist  */
464adc4f0dbSShawn McCarney static std::string getState(const InventoryItem* inventoryItem)
465adc4f0dbSShawn McCarney {
466adc4f0dbSShawn McCarney     if ((inventoryItem != nullptr) && !(inventoryItem->isPresent))
467adc4f0dbSShawn McCarney     {
468adc4f0dbSShawn McCarney         return "Absent";
469adc4f0dbSShawn McCarney     }
47034dd179eSJames Feist 
471adc4f0dbSShawn McCarney     return "Enabled";
472adc4f0dbSShawn McCarney }
473adc4f0dbSShawn McCarney 
474adc4f0dbSShawn McCarney /**
475adc4f0dbSShawn McCarney  * @brief Returns the Redfish Health value for the specified sensor.
476adc4f0dbSShawn McCarney  * @param sensorJson Sensor JSON object.
477adc4f0dbSShawn McCarney  * @param interfacesDict Map of all sensor interfaces.
478adc4f0dbSShawn McCarney  * @param inventoryItem D-Bus inventory item associated with the sensor.  Will
479adc4f0dbSShawn McCarney  * be nullptr if no associated inventory item was found.
480adc4f0dbSShawn McCarney  * @return Health value for sensor.
481adc4f0dbSShawn McCarney  */
48234dd179eSJames Feist static std::string getHealth(
483adc4f0dbSShawn McCarney     nlohmann::json& sensorJson,
48434dd179eSJames Feist     const boost::container::flat_map<
48534dd179eSJames Feist         std::string, boost::container::flat_map<std::string, SensorVariant>>&
486adc4f0dbSShawn McCarney         interfacesDict,
487adc4f0dbSShawn McCarney     const InventoryItem* inventoryItem)
48834dd179eSJames Feist {
489adc4f0dbSShawn McCarney     // Get current health value (if any) in the sensor JSON object.  Some JSON
490adc4f0dbSShawn McCarney     // objects contain multiple sensors (such as PowerSupplies).  We want to set
491adc4f0dbSShawn McCarney     // the overall health to be the most severe of any of the sensors.
492adc4f0dbSShawn McCarney     std::string currentHealth;
493adc4f0dbSShawn McCarney     auto statusIt = sensorJson.find("Status");
494adc4f0dbSShawn McCarney     if (statusIt != sensorJson.end())
495adc4f0dbSShawn McCarney     {
496adc4f0dbSShawn McCarney         auto healthIt = statusIt->find("Health");
497adc4f0dbSShawn McCarney         if (healthIt != statusIt->end())
498adc4f0dbSShawn McCarney         {
499adc4f0dbSShawn McCarney             std::string* health = healthIt->get_ptr<std::string*>();
500adc4f0dbSShawn McCarney             if (health != nullptr)
501adc4f0dbSShawn McCarney             {
502adc4f0dbSShawn McCarney                 currentHealth = *health;
503adc4f0dbSShawn McCarney             }
504adc4f0dbSShawn McCarney         }
505adc4f0dbSShawn McCarney     }
506adc4f0dbSShawn McCarney 
507adc4f0dbSShawn McCarney     // If current health in JSON object is already Critical, return that.  This
508adc4f0dbSShawn McCarney     // should override the sensor health, which might be less severe.
509adc4f0dbSShawn McCarney     if (currentHealth == "Critical")
510adc4f0dbSShawn McCarney     {
511adc4f0dbSShawn McCarney         return "Critical";
512adc4f0dbSShawn McCarney     }
513adc4f0dbSShawn McCarney 
514adc4f0dbSShawn McCarney     // Check if sensor has critical threshold alarm
51534dd179eSJames Feist     auto criticalThresholdIt =
51634dd179eSJames Feist         interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Critical");
51734dd179eSJames Feist     if (criticalThresholdIt != interfacesDict.end())
51834dd179eSJames Feist     {
51934dd179eSJames Feist         auto thresholdHighIt =
52034dd179eSJames Feist             criticalThresholdIt->second.find("CriticalAlarmHigh");
52134dd179eSJames Feist         auto thresholdLowIt =
52234dd179eSJames Feist             criticalThresholdIt->second.find("CriticalAlarmLow");
52334dd179eSJames Feist         if (thresholdHighIt != criticalThresholdIt->second.end())
52434dd179eSJames Feist         {
52534dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdHighIt->second);
52634dd179eSJames Feist             if (asserted == nullptr)
52734dd179eSJames Feist             {
52834dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
52934dd179eSJames Feist             }
53034dd179eSJames Feist             else if (*asserted)
53134dd179eSJames Feist             {
53234dd179eSJames Feist                 return "Critical";
53334dd179eSJames Feist             }
53434dd179eSJames Feist         }
53534dd179eSJames Feist         if (thresholdLowIt != criticalThresholdIt->second.end())
53634dd179eSJames Feist         {
53734dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdLowIt->second);
53834dd179eSJames Feist             if (asserted == nullptr)
53934dd179eSJames Feist             {
54034dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
54134dd179eSJames Feist             }
54234dd179eSJames Feist             else if (*asserted)
54334dd179eSJames Feist             {
54434dd179eSJames Feist                 return "Critical";
54534dd179eSJames Feist             }
54634dd179eSJames Feist         }
54734dd179eSJames Feist     }
54834dd179eSJames Feist 
549adc4f0dbSShawn McCarney     // Check if associated inventory item is not functional
550adc4f0dbSShawn McCarney     if ((inventoryItem != nullptr) && !(inventoryItem->isFunctional))
551adc4f0dbSShawn McCarney     {
552adc4f0dbSShawn McCarney         return "Critical";
553adc4f0dbSShawn McCarney     }
554adc4f0dbSShawn McCarney 
555adc4f0dbSShawn McCarney     // If current health in JSON object is already Warning, return that.  This
556adc4f0dbSShawn McCarney     // should override the sensor status, which might be less severe.
557adc4f0dbSShawn McCarney     if (currentHealth == "Warning")
558adc4f0dbSShawn McCarney     {
559adc4f0dbSShawn McCarney         return "Warning";
560adc4f0dbSShawn McCarney     }
561adc4f0dbSShawn McCarney 
562adc4f0dbSShawn McCarney     // Check if sensor has warning threshold alarm
56334dd179eSJames Feist     auto warningThresholdIt =
56434dd179eSJames Feist         interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Warning");
56534dd179eSJames Feist     if (warningThresholdIt != interfacesDict.end())
56634dd179eSJames Feist     {
56734dd179eSJames Feist         auto thresholdHighIt =
56834dd179eSJames Feist             warningThresholdIt->second.find("WarningAlarmHigh");
56934dd179eSJames Feist         auto thresholdLowIt =
57034dd179eSJames Feist             warningThresholdIt->second.find("WarningAlarmLow");
57134dd179eSJames Feist         if (thresholdHighIt != warningThresholdIt->second.end())
57234dd179eSJames Feist         {
57334dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdHighIt->second);
57434dd179eSJames Feist             if (asserted == nullptr)
57534dd179eSJames Feist             {
57634dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
57734dd179eSJames Feist             }
57834dd179eSJames Feist             else if (*asserted)
57934dd179eSJames Feist             {
58034dd179eSJames Feist                 return "Warning";
58134dd179eSJames Feist             }
58234dd179eSJames Feist         }
58334dd179eSJames Feist         if (thresholdLowIt != warningThresholdIt->second.end())
58434dd179eSJames Feist         {
58534dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdLowIt->second);
58634dd179eSJames Feist             if (asserted == nullptr)
58734dd179eSJames Feist             {
58834dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
58934dd179eSJames Feist             }
59034dd179eSJames Feist             else if (*asserted)
59134dd179eSJames Feist             {
59234dd179eSJames Feist                 return "Warning";
59334dd179eSJames Feist             }
59434dd179eSJames Feist         }
59534dd179eSJames Feist     }
596adc4f0dbSShawn McCarney 
59734dd179eSJames Feist     return "OK";
59834dd179eSJames Feist }
59934dd179eSJames Feist 
60034dd179eSJames Feist /**
60108777fb0SLewanczyk, Dawid  * @brief Builds a json sensor representation of a sensor.
60208777fb0SLewanczyk, Dawid  * @param sensorName  The name of the sensor to be built
603274fad5aSGunnar Mills  * @param sensorType  The type (temperature, fan_tach, etc) of the sensor to
60408777fb0SLewanczyk, Dawid  * build
60595a3ecadSAnthony Wilson  * @param sensorSchema  The schema (Power, Thermal, etc) being associated with
60695a3ecadSAnthony Wilson  * the sensor to build
60708777fb0SLewanczyk, Dawid  * @param interfacesDict  A dictionary of the interfaces and properties of said
60808777fb0SLewanczyk, Dawid  * interfaces to be built from
60908777fb0SLewanczyk, Dawid  * @param sensor_json  The json object to fill
610adc4f0dbSShawn McCarney  * @param inventoryItem D-Bus inventory item associated with the sensor.  Will
611adc4f0dbSShawn McCarney  * be nullptr if no associated inventory item was found.
61208777fb0SLewanczyk, Dawid  */
61308777fb0SLewanczyk, Dawid void objectInterfacesToJson(
61408777fb0SLewanczyk, Dawid     const std::string& sensorName, const std::string& sensorType,
61595a3ecadSAnthony Wilson     const std::string& sensorSchema,
61608777fb0SLewanczyk, Dawid     const boost::container::flat_map<
617aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>&
61808777fb0SLewanczyk, Dawid         interfacesDict,
619adc4f0dbSShawn McCarney     nlohmann::json& sensor_json, InventoryItem* inventoryItem)
6201abe55efSEd Tanous {
62108777fb0SLewanczyk, Dawid     // We need a value interface before we can do anything with it
62255c7b7a2SEd Tanous     auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
6231abe55efSEd Tanous     if (valueIt == interfacesDict.end())
6241abe55efSEd Tanous     {
62555c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface";
62608777fb0SLewanczyk, Dawid         return;
62708777fb0SLewanczyk, Dawid     }
62808777fb0SLewanczyk, Dawid 
62908777fb0SLewanczyk, Dawid     // Assume values exist as is (10^0 == 1) if no scale exists
63008777fb0SLewanczyk, Dawid     int64_t scaleMultiplier = 0;
63108777fb0SLewanczyk, Dawid 
63255c7b7a2SEd Tanous     auto scaleIt = valueIt->second.find("Scale");
63308777fb0SLewanczyk, Dawid     // If a scale exists, pull value as int64, and use the scaling.
6341abe55efSEd Tanous     if (scaleIt != valueIt->second.end())
6351abe55efSEd Tanous     {
636abf2add6SEd Tanous         const int64_t* int64Value = std::get_if<int64_t>(&scaleIt->second);
6371abe55efSEd Tanous         if (int64Value != nullptr)
6381abe55efSEd Tanous         {
63908777fb0SLewanczyk, Dawid             scaleMultiplier = *int64Value;
64008777fb0SLewanczyk, Dawid         }
64108777fb0SLewanczyk, Dawid     }
64208777fb0SLewanczyk, Dawid 
64395a3ecadSAnthony Wilson     if (sensorSchema == "Sensors")
644adc4f0dbSShawn McCarney     {
64595a3ecadSAnthony Wilson         // For sensors in SensorCollection we set Id instead of MemberId,
64695a3ecadSAnthony Wilson         // including power sensors.
64795a3ecadSAnthony Wilson         sensor_json["Id"] = sensorName;
64895a3ecadSAnthony Wilson         sensor_json["Name"] = boost::replace_all_copy(sensorName, "_", " ");
64995a3ecadSAnthony Wilson     }
65095a3ecadSAnthony Wilson     else if (sensorType != "power")
65195a3ecadSAnthony Wilson     {
65295a3ecadSAnthony Wilson         // Set MemberId and Name for non-power sensors.  For PowerSupplies and
65395a3ecadSAnthony Wilson         // PowerControl, those properties have more general values because
65495a3ecadSAnthony Wilson         // multiple sensors can be stored in the same JSON object.
65508777fb0SLewanczyk, Dawid         sensor_json["MemberId"] = sensorName;
656e742b6ccSEd Tanous         sensor_json["Name"] = boost::replace_all_copy(sensorName, "_", " ");
657adc4f0dbSShawn McCarney     }
658e742b6ccSEd Tanous 
659adc4f0dbSShawn McCarney     sensor_json["Status"]["State"] = getState(inventoryItem);
660adc4f0dbSShawn McCarney     sensor_json["Status"]["Health"] =
661adc4f0dbSShawn McCarney         getHealth(sensor_json, interfacesDict, inventoryItem);
66208777fb0SLewanczyk, Dawid 
66308777fb0SLewanczyk, Dawid     // Parameter to set to override the type we get from dbus, and force it to
66408777fb0SLewanczyk, Dawid     // int, regardless of what is available.  This is used for schemas like fan,
66508777fb0SLewanczyk, Dawid     // that require integers, not floats.
66608777fb0SLewanczyk, Dawid     bool forceToInt = false;
66708777fb0SLewanczyk, Dawid 
6683929aca1SAnthony Wilson     nlohmann::json::json_pointer unit("/Reading");
66995a3ecadSAnthony Wilson     if (sensorSchema == "Sensors")
67095a3ecadSAnthony Wilson     {
67195a3ecadSAnthony Wilson         sensor_json["@odata.type"] = "#Sensor.v1_0_0.Sensor";
67295a3ecadSAnthony Wilson         sensor_json["@odata.context"] = "/redfish/v1/$metadata#Sensor.Sensor";
67395a3ecadSAnthony Wilson         if (sensorType == "power")
67495a3ecadSAnthony Wilson         {
67595a3ecadSAnthony Wilson             sensor_json["ReadingUnits"] = "Watts";
67695a3ecadSAnthony Wilson         }
67795a3ecadSAnthony Wilson         else if (sensorType == "current")
67895a3ecadSAnthony Wilson         {
67995a3ecadSAnthony Wilson             sensor_json["ReadingUnits"] = "Amperes";
68095a3ecadSAnthony Wilson         }
68195a3ecadSAnthony Wilson     }
68295a3ecadSAnthony Wilson     else if (sensorType == "temperature")
6831abe55efSEd Tanous     {
6843929aca1SAnthony Wilson         unit = "/ReadingCelsius"_json_pointer;
6857885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature";
68608777fb0SLewanczyk, Dawid         // TODO(ed) Documentation says that path should be type fan_tach,
68708777fb0SLewanczyk, Dawid         // implementation seems to implement fan
6881abe55efSEd Tanous     }
6891abe55efSEd Tanous     else if (sensorType == "fan" || sensorType == "fan_tach")
6901abe55efSEd Tanous     {
6913929aca1SAnthony Wilson         unit = "/Reading"_json_pointer;
69208777fb0SLewanczyk, Dawid         sensor_json["ReadingUnits"] = "RPM";
6937885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
69408777fb0SLewanczyk, Dawid         forceToInt = true;
6951abe55efSEd Tanous     }
6966f6d0d32SEd Tanous     else if (sensorType == "fan_pwm")
6976f6d0d32SEd Tanous     {
6983929aca1SAnthony Wilson         unit = "/Reading"_json_pointer;
6996f6d0d32SEd Tanous         sensor_json["ReadingUnits"] = "Percent";
7006f6d0d32SEd Tanous         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
7016f6d0d32SEd Tanous         forceToInt = true;
7026f6d0d32SEd Tanous     }
7031abe55efSEd Tanous     else if (sensorType == "voltage")
7041abe55efSEd Tanous     {
7053929aca1SAnthony Wilson         unit = "/ReadingVolts"_json_pointer;
7067885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage";
7071abe55efSEd Tanous     }
7082474adfaSEd Tanous     else if (sensorType == "power")
7092474adfaSEd Tanous     {
71049c53ac9SJohnathan Mantey         std::string sensorNameLower =
71149c53ac9SJohnathan Mantey             boost::algorithm::to_lower_copy(sensorName);
71249c53ac9SJohnathan Mantey 
713028f7ebcSEddie James         if (!sensorName.compare("total_power"))
714028f7ebcSEddie James         {
7157ab06f49SGunnar Mills             sensor_json["@odata.type"] = "#Power.v1_0_0.PowerControl";
7167ab06f49SGunnar Mills             // Put multiple "sensors" into a single PowerControl, so have
7177ab06f49SGunnar Mills             // generic names for MemberId and Name. Follows Redfish mockup.
7187ab06f49SGunnar Mills             sensor_json["MemberId"] = "0";
7197ab06f49SGunnar Mills             sensor_json["Name"] = "Chassis Power Control";
7203929aca1SAnthony Wilson             unit = "/PowerConsumedWatts"_json_pointer;
721028f7ebcSEddie James         }
722028f7ebcSEddie James         else if (sensorNameLower.find("input") != std::string::npos)
72349c53ac9SJohnathan Mantey         {
7243929aca1SAnthony Wilson             unit = "/PowerInputWatts"_json_pointer;
72549c53ac9SJohnathan Mantey         }
72649c53ac9SJohnathan Mantey         else
72749c53ac9SJohnathan Mantey         {
7283929aca1SAnthony Wilson             unit = "/PowerOutputWatts"_json_pointer;
72949c53ac9SJohnathan Mantey         }
7302474adfaSEd Tanous     }
7311abe55efSEd Tanous     else
7321abe55efSEd Tanous     {
73355c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
73408777fb0SLewanczyk, Dawid         return;
73508777fb0SLewanczyk, Dawid     }
73608777fb0SLewanczyk, Dawid     // Map of dbus interface name, dbus property name and redfish property_name
7373929aca1SAnthony Wilson     std::vector<
7383929aca1SAnthony Wilson         std::tuple<const char*, const char*, nlohmann::json::json_pointer>>
7393929aca1SAnthony Wilson         properties;
74008777fb0SLewanczyk, Dawid     properties.reserve(7);
74108777fb0SLewanczyk, Dawid 
74208777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
743de629b6eSShawn McCarney 
7443929aca1SAnthony Wilson     if (sensorSchema == "Sensors")
7453929aca1SAnthony Wilson     {
7463929aca1SAnthony Wilson         properties.emplace_back(
7473929aca1SAnthony Wilson             "xyz.openbmc_project.Sensor.Threshold.Warning", "WarningHigh",
7483929aca1SAnthony Wilson             "/Thresholds/UpperCaution/Reading"_json_pointer);
7493929aca1SAnthony Wilson         properties.emplace_back(
7503929aca1SAnthony Wilson             "xyz.openbmc_project.Sensor.Threshold.Warning", "WarningLow",
7513929aca1SAnthony Wilson             "/Thresholds/LowerCaution/Reading"_json_pointer);
7523929aca1SAnthony Wilson         properties.emplace_back(
7533929aca1SAnthony Wilson             "xyz.openbmc_project.Sensor.Threshold.Critical", "CriticalHigh",
7543929aca1SAnthony Wilson             "/Thresholds/UpperCritical/Reading"_json_pointer);
7553929aca1SAnthony Wilson         properties.emplace_back(
7563929aca1SAnthony Wilson             "xyz.openbmc_project.Sensor.Threshold.Critical", "CriticalLow",
7573929aca1SAnthony Wilson             "/Thresholds/LowerCritical/Reading"_json_pointer);
7583929aca1SAnthony Wilson     }
7593929aca1SAnthony Wilson     else if (sensorType != "power")
760de629b6eSShawn McCarney     {
76108777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
7623929aca1SAnthony Wilson                                 "WarningHigh",
7633929aca1SAnthony Wilson                                 "/UpperThresholdNonCritical"_json_pointer);
76408777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
7653929aca1SAnthony Wilson                                 "WarningLow",
7663929aca1SAnthony Wilson                                 "/LowerThresholdNonCritical"_json_pointer);
76708777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
7683929aca1SAnthony Wilson                                 "CriticalHigh",
7693929aca1SAnthony Wilson                                 "/UpperThresholdCritical"_json_pointer);
77008777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
7713929aca1SAnthony Wilson                                 "CriticalLow",
7723929aca1SAnthony Wilson                                 "/LowerThresholdCritical"_json_pointer);
773de629b6eSShawn McCarney     }
77408777fb0SLewanczyk, Dawid 
7752474adfaSEd Tanous     // TODO Need to get UpperThresholdFatal and LowerThresholdFatal
7762474adfaSEd Tanous 
77795a3ecadSAnthony Wilson     if (sensorSchema == "Sensors")
77895a3ecadSAnthony Wilson     {
77995a3ecadSAnthony Wilson         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
7803929aca1SAnthony Wilson                                 "/ReadingRangeMin"_json_pointer);
78195a3ecadSAnthony Wilson         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
7823929aca1SAnthony Wilson                                 "/ReadingRangeMax"_json_pointer);
78395a3ecadSAnthony Wilson     }
78495a3ecadSAnthony Wilson     else if (sensorType == "temperature")
7851abe55efSEd Tanous     {
78608777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
7873929aca1SAnthony Wilson                                 "/MinReadingRangeTemp"_json_pointer);
78808777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
7893929aca1SAnthony Wilson                                 "/MaxReadingRangeTemp"_json_pointer);
7901abe55efSEd Tanous     }
791adc4f0dbSShawn McCarney     else if (sensorType != "power")
7921abe55efSEd Tanous     {
79308777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
7943929aca1SAnthony Wilson                                 "/MinReadingRange"_json_pointer);
79508777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
7963929aca1SAnthony Wilson                                 "/MaxReadingRange"_json_pointer);
79708777fb0SLewanczyk, Dawid     }
79808777fb0SLewanczyk, Dawid 
7993929aca1SAnthony Wilson     for (const std::tuple<const char*, const char*,
8003929aca1SAnthony Wilson                           nlohmann::json::json_pointer>& p : properties)
8011abe55efSEd Tanous     {
80208777fb0SLewanczyk, Dawid         auto interfaceProperties = interfacesDict.find(std::get<0>(p));
8031abe55efSEd Tanous         if (interfaceProperties != interfacesDict.end())
8041abe55efSEd Tanous         {
805*271584abSEd Tanous             auto thisValueIt = interfaceProperties->second.find(std::get<1>(p));
806*271584abSEd Tanous             if (thisValueIt != interfaceProperties->second.end())
8071abe55efSEd Tanous             {
808*271584abSEd Tanous                 const SensorVariant& valueVariant = thisValueIt->second;
8093929aca1SAnthony Wilson 
8103929aca1SAnthony Wilson                 // The property we want to set may be nested json, so use
8113929aca1SAnthony Wilson                 // a json_pointer for easy indexing into the json structure.
8123929aca1SAnthony Wilson                 const nlohmann::json::json_pointer& key = std::get<2>(p);
8133929aca1SAnthony Wilson 
81408777fb0SLewanczyk, Dawid                 // Attempt to pull the int64 directly
815abf2add6SEd Tanous                 const int64_t* int64Value = std::get_if<int64_t>(&valueVariant);
81608777fb0SLewanczyk, Dawid 
817abf2add6SEd Tanous                 const double* doubleValue = std::get_if<double>(&valueVariant);
818028f7ebcSEddie James                 const uint32_t* uValue = std::get_if<uint32_t>(&valueVariant);
8196f6d0d32SEd Tanous                 double temp = 0.0;
8206f6d0d32SEd Tanous                 if (int64Value != nullptr)
8211abe55efSEd Tanous                 {
822*271584abSEd Tanous                     temp = static_cast<double>(*int64Value);
8236f6d0d32SEd Tanous                 }
8246f6d0d32SEd Tanous                 else if (doubleValue != nullptr)
8251abe55efSEd Tanous                 {
8266f6d0d32SEd Tanous                     temp = *doubleValue;
8271abe55efSEd Tanous                 }
828028f7ebcSEddie James                 else if (uValue != nullptr)
829028f7ebcSEddie James                 {
830028f7ebcSEddie James                     temp = *uValue;
831028f7ebcSEddie James                 }
8321abe55efSEd Tanous                 else
8331abe55efSEd Tanous                 {
8346f6d0d32SEd Tanous                     BMCWEB_LOG_ERROR
8356f6d0d32SEd Tanous                         << "Got value interface that wasn't int or double";
8366f6d0d32SEd Tanous                     continue;
83708777fb0SLewanczyk, Dawid                 }
8386f6d0d32SEd Tanous                 temp = temp * std::pow(10, scaleMultiplier);
8396f6d0d32SEd Tanous                 if (forceToInt)
8406f6d0d32SEd Tanous                 {
8413929aca1SAnthony Wilson                     sensor_json[key] = static_cast<int64_t>(temp);
8426f6d0d32SEd Tanous                 }
8436f6d0d32SEd Tanous                 else
8446f6d0d32SEd Tanous                 {
8453929aca1SAnthony Wilson                     sensor_json[key] = temp;
84608777fb0SLewanczyk, Dawid                 }
84708777fb0SLewanczyk, Dawid             }
84808777fb0SLewanczyk, Dawid         }
84908777fb0SLewanczyk, Dawid     }
85055c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
85108777fb0SLewanczyk, Dawid }
85208777fb0SLewanczyk, Dawid 
8538bd25ccdSJames Feist static void
8548bd25ccdSJames Feist     populateFanRedundancy(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp)
8558bd25ccdSJames Feist {
8568bd25ccdSJames Feist     crow::connections::systemBus->async_method_call(
8578bd25ccdSJames Feist         [sensorsAsyncResp](const boost::system::error_code ec,
8588bd25ccdSJames Feist                            const GetSubTreeType& resp) {
8598bd25ccdSJames Feist             if (ec)
8608bd25ccdSJames Feist             {
8618bd25ccdSJames Feist                 return; // don't have to have this interface
8628bd25ccdSJames Feist             }
863e278c18fSEd Tanous             for (const std::pair<std::string,
864e278c18fSEd Tanous                                  std::vector<std::pair<
865e278c18fSEd Tanous                                      std::string, std::vector<std::string>>>>&
866e278c18fSEd Tanous                      pathPair : resp)
8678bd25ccdSJames Feist             {
868e278c18fSEd Tanous                 const std::string& path = pathPair.first;
869e278c18fSEd Tanous                 const std::vector<
870e278c18fSEd Tanous                     std::pair<std::string, std::vector<std::string>>>& objDict =
871e278c18fSEd Tanous                     pathPair.second;
8728bd25ccdSJames Feist                 if (objDict.empty())
8738bd25ccdSJames Feist                 {
8748bd25ccdSJames Feist                     continue; // this should be impossible
8758bd25ccdSJames Feist                 }
8768bd25ccdSJames Feist 
8778bd25ccdSJames Feist                 const std::string& owner = objDict.begin()->first;
8788bd25ccdSJames Feist                 crow::connections::systemBus->async_method_call(
8798bd25ccdSJames Feist                     [path, owner,
880*271584abSEd Tanous                      sensorsAsyncResp](const boost::system::error_code e,
8818bd25ccdSJames Feist                                        std::variant<std::vector<std::string>>
8828bd25ccdSJames Feist                                            variantEndpoints) {
883*271584abSEd Tanous                         if (e)
8848bd25ccdSJames Feist                         {
8858bd25ccdSJames Feist                             return; // if they don't have an association we
8868bd25ccdSJames Feist                                     // can't tell what chassis is
8878bd25ccdSJames Feist                         }
8888bd25ccdSJames Feist                         // verify part of the right chassis
8898bd25ccdSJames Feist                         auto endpoints = std::get_if<std::vector<std::string>>(
8908bd25ccdSJames Feist                             &variantEndpoints);
8918bd25ccdSJames Feist 
8928bd25ccdSJames Feist                         if (endpoints == nullptr)
8938bd25ccdSJames Feist                         {
8948bd25ccdSJames Feist                             BMCWEB_LOG_ERROR << "Invalid association interface";
8958bd25ccdSJames Feist                             messages::internalError(sensorsAsyncResp->res);
8968bd25ccdSJames Feist                             return;
8978bd25ccdSJames Feist                         }
8988bd25ccdSJames Feist 
8998bd25ccdSJames Feist                         auto found = std::find_if(
9008bd25ccdSJames Feist                             endpoints->begin(), endpoints->end(),
9018bd25ccdSJames Feist                             [sensorsAsyncResp](const std::string& entry) {
9028bd25ccdSJames Feist                                 return entry.find(
9038bd25ccdSJames Feist                                            sensorsAsyncResp->chassisId) !=
9048bd25ccdSJames Feist                                        std::string::npos;
9058bd25ccdSJames Feist                             });
9068bd25ccdSJames Feist 
9078bd25ccdSJames Feist                         if (found == endpoints->end())
9088bd25ccdSJames Feist                         {
9098bd25ccdSJames Feist                             return;
9108bd25ccdSJames Feist                         }
9118bd25ccdSJames Feist                         crow::connections::systemBus->async_method_call(
9128bd25ccdSJames Feist                             [path, sensorsAsyncResp](
913*271584abSEd Tanous                                 const boost::system::error_code& err,
9148bd25ccdSJames Feist                                 const boost::container::flat_map<
9158bd25ccdSJames Feist                                     std::string,
9168bd25ccdSJames Feist                                     std::variant<uint8_t,
9178bd25ccdSJames Feist                                                  std::vector<std::string>,
9188bd25ccdSJames Feist                                                  std::string>>& ret) {
919*271584abSEd Tanous                                 if (err)
9208bd25ccdSJames Feist                                 {
9218bd25ccdSJames Feist                                     return; // don't have to have this
9228bd25ccdSJames Feist                                             // interface
9238bd25ccdSJames Feist                                 }
9248bd25ccdSJames Feist                                 auto findFailures = ret.find("AllowedFailures");
9258bd25ccdSJames Feist                                 auto findCollection = ret.find("Collection");
9268bd25ccdSJames Feist                                 auto findStatus = ret.find("Status");
9278bd25ccdSJames Feist 
9288bd25ccdSJames Feist                                 if (findFailures == ret.end() ||
9298bd25ccdSJames Feist                                     findCollection == ret.end() ||
9308bd25ccdSJames Feist                                     findStatus == ret.end())
9318bd25ccdSJames Feist                                 {
9328bd25ccdSJames Feist                                     BMCWEB_LOG_ERROR
9338bd25ccdSJames Feist                                         << "Invalid redundancy interface";
9348bd25ccdSJames Feist                                     messages::internalError(
9358bd25ccdSJames Feist                                         sensorsAsyncResp->res);
9368bd25ccdSJames Feist                                     return;
9378bd25ccdSJames Feist                                 }
9388bd25ccdSJames Feist 
9398bd25ccdSJames Feist                                 auto allowedFailures = std::get_if<uint8_t>(
9408bd25ccdSJames Feist                                     &(findFailures->second));
9418bd25ccdSJames Feist                                 auto collection =
9428bd25ccdSJames Feist                                     std::get_if<std::vector<std::string>>(
9438bd25ccdSJames Feist                                         &(findCollection->second));
9448bd25ccdSJames Feist                                 auto status = std::get_if<std::string>(
9458bd25ccdSJames Feist                                     &(findStatus->second));
9468bd25ccdSJames Feist 
9478bd25ccdSJames Feist                                 if (allowedFailures == nullptr ||
9488bd25ccdSJames Feist                                     collection == nullptr || status == nullptr)
9498bd25ccdSJames Feist                                 {
9508bd25ccdSJames Feist 
9518bd25ccdSJames Feist                                     BMCWEB_LOG_ERROR
9528bd25ccdSJames Feist                                         << "Invalid redundancy interface "
9538bd25ccdSJames Feist                                            "types";
9548bd25ccdSJames Feist                                     messages::internalError(
9558bd25ccdSJames Feist                                         sensorsAsyncResp->res);
9568bd25ccdSJames Feist                                     return;
9578bd25ccdSJames Feist                                 }
9588bd25ccdSJames Feist                                 size_t lastSlash = path.rfind("/");
9598bd25ccdSJames Feist                                 if (lastSlash == std::string::npos)
9608bd25ccdSJames Feist                                 {
9618bd25ccdSJames Feist                                     // this should be impossible
9628bd25ccdSJames Feist                                     messages::internalError(
9638bd25ccdSJames Feist                                         sensorsAsyncResp->res);
9648bd25ccdSJames Feist                                     return;
9658bd25ccdSJames Feist                                 }
9668bd25ccdSJames Feist                                 std::string name = path.substr(lastSlash + 1);
9678bd25ccdSJames Feist                                 std::replace(name.begin(), name.end(), '_',
9688bd25ccdSJames Feist                                              ' ');
9698bd25ccdSJames Feist 
9708bd25ccdSJames Feist                                 std::string health;
9718bd25ccdSJames Feist 
9728bd25ccdSJames Feist                                 if (boost::ends_with(*status, "Full"))
9738bd25ccdSJames Feist                                 {
9748bd25ccdSJames Feist                                     health = "OK";
9758bd25ccdSJames Feist                                 }
9768bd25ccdSJames Feist                                 else if (boost::ends_with(*status, "Degraded"))
9778bd25ccdSJames Feist                                 {
9788bd25ccdSJames Feist                                     health = "Warning";
9798bd25ccdSJames Feist                                 }
9808bd25ccdSJames Feist                                 else
9818bd25ccdSJames Feist                                 {
9828bd25ccdSJames Feist                                     health = "Critical";
9838bd25ccdSJames Feist                                 }
9848bd25ccdSJames Feist                                 std::vector<nlohmann::json> redfishCollection;
9858bd25ccdSJames Feist                                 const auto& fanRedfish =
9868bd25ccdSJames Feist                                     sensorsAsyncResp->res.jsonValue["Fans"];
9878bd25ccdSJames Feist                                 for (const std::string& item : *collection)
9888bd25ccdSJames Feist                                 {
9898bd25ccdSJames Feist                                     lastSlash = item.rfind("/");
9908bd25ccdSJames Feist                                     // make a copy as collection is const
9918bd25ccdSJames Feist                                     std::string itemName =
9928bd25ccdSJames Feist                                         item.substr(lastSlash + 1);
9938bd25ccdSJames Feist                                     /*
9948bd25ccdSJames Feist                                     todo(ed): merge patch that fixes the names
9958bd25ccdSJames Feist                                     std::replace(itemName.begin(),
9968bd25ccdSJames Feist                                                  itemName.end(), '_', ' ');*/
9978bd25ccdSJames Feist                                     auto schemaItem = std::find_if(
9988bd25ccdSJames Feist                                         fanRedfish.begin(), fanRedfish.end(),
9998bd25ccdSJames Feist                                         [itemName](const nlohmann::json& fan) {
10008bd25ccdSJames Feist                                             return fan["MemberId"] == itemName;
10018bd25ccdSJames Feist                                         });
10028bd25ccdSJames Feist                                     if (schemaItem != fanRedfish.end())
10038bd25ccdSJames Feist                                     {
10048bd25ccdSJames Feist                                         redfishCollection.push_back(
10058bd25ccdSJames Feist                                             {{"@odata.id",
10068bd25ccdSJames Feist                                               (*schemaItem)["@odata.id"]}});
10078bd25ccdSJames Feist                                     }
10088bd25ccdSJames Feist                                     else
10098bd25ccdSJames Feist                                     {
10108bd25ccdSJames Feist                                         BMCWEB_LOG_ERROR
10118bd25ccdSJames Feist                                             << "failed to find fan in schema";
10128bd25ccdSJames Feist                                         messages::internalError(
10138bd25ccdSJames Feist                                             sensorsAsyncResp->res);
10148bd25ccdSJames Feist                                         return;
10158bd25ccdSJames Feist                                     }
10168bd25ccdSJames Feist                                 }
10178bd25ccdSJames Feist 
1018*271584abSEd Tanous                                 nlohmann::json& jResp =
1019*271584abSEd Tanous                                     sensorsAsyncResp->res
10208bd25ccdSJames Feist                                         .jsonValue["Redundancy"];
1021*271584abSEd Tanous                                 jResp.push_back(
10228bd25ccdSJames Feist                                     {{"@odata.id",
10238bd25ccdSJames Feist                                       "/refish/v1/Chassis/" +
10248bd25ccdSJames Feist                                           sensorsAsyncResp->chassisId + "/" +
10258bd25ccdSJames Feist                                           sensorsAsyncResp->chassisSubNode +
10268bd25ccdSJames Feist                                           "#/Redundancy/" +
1027*271584abSEd Tanous                                           std::to_string(jResp.size())},
10288bd25ccdSJames Feist                                      {"@odata.type",
10298bd25ccdSJames Feist                                       "#Redundancy.v1_3_2.Redundancy"},
10308bd25ccdSJames Feist                                      {"MinNumNeeded",
10318bd25ccdSJames Feist                                       collection->size() - *allowedFailures},
10328bd25ccdSJames Feist                                      {"MemberId", name},
10338bd25ccdSJames Feist                                      {"Mode", "N+m"},
10348bd25ccdSJames Feist                                      {"Name", name},
10358bd25ccdSJames Feist                                      {"RedundancySet", redfishCollection},
10368bd25ccdSJames Feist                                      {"Status",
10378bd25ccdSJames Feist                                       {{"Health", health},
10388bd25ccdSJames Feist                                        {"State", "Enabled"}}}});
10398bd25ccdSJames Feist                             },
10408bd25ccdSJames Feist                             owner, path, "org.freedesktop.DBus.Properties",
10418bd25ccdSJames Feist                             "GetAll",
10428bd25ccdSJames Feist                             "xyz.openbmc_project.Control.FanRedundancy");
10438bd25ccdSJames Feist                     },
104402e92e32SJames Feist                     "xyz.openbmc_project.ObjectMapper", path + "/chassis",
10458bd25ccdSJames Feist                     "org.freedesktop.DBus.Properties", "Get",
10468bd25ccdSJames Feist                     "xyz.openbmc_project.Association", "endpoints");
10478bd25ccdSJames Feist             }
10488bd25ccdSJames Feist         },
10498bd25ccdSJames Feist         "xyz.openbmc_project.ObjectMapper",
10508bd25ccdSJames Feist         "/xyz/openbmc_project/object_mapper",
10518bd25ccdSJames Feist         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
10528bd25ccdSJames Feist         "/xyz/openbmc_project/control", 2,
10538bd25ccdSJames Feist         std::array<const char*, 1>{
10548bd25ccdSJames Feist             "xyz.openbmc_project.Control.FanRedundancy"});
10558bd25ccdSJames Feist }
10568bd25ccdSJames Feist 
105749c53ac9SJohnathan Mantey void sortJSONResponse(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
105849c53ac9SJohnathan Mantey {
105949c53ac9SJohnathan Mantey     nlohmann::json& response = SensorsAsyncResp->res.jsonValue;
106049c53ac9SJohnathan Mantey     std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
106149c53ac9SJohnathan Mantey     if (SensorsAsyncResp->chassisSubNode == "Power")
106249c53ac9SJohnathan Mantey     {
106349c53ac9SJohnathan Mantey         sensorHeaders = {"Voltages", "PowerSupplies"};
106449c53ac9SJohnathan Mantey     }
106549c53ac9SJohnathan Mantey     for (const std::string& sensorGroup : sensorHeaders)
106649c53ac9SJohnathan Mantey     {
106749c53ac9SJohnathan Mantey         nlohmann::json::iterator entry = response.find(sensorGroup);
106849c53ac9SJohnathan Mantey         if (entry != response.end())
106949c53ac9SJohnathan Mantey         {
107049c53ac9SJohnathan Mantey             std::sort(entry->begin(), entry->end(),
107149c53ac9SJohnathan Mantey                       [](nlohmann::json& c1, nlohmann::json& c2) {
107249c53ac9SJohnathan Mantey                           return c1["Name"] < c2["Name"];
107349c53ac9SJohnathan Mantey                       });
107449c53ac9SJohnathan Mantey 
107549c53ac9SJohnathan Mantey             // add the index counts to the end of each entry
107649c53ac9SJohnathan Mantey             size_t count = 0;
107749c53ac9SJohnathan Mantey             for (nlohmann::json& sensorJson : *entry)
107849c53ac9SJohnathan Mantey             {
107949c53ac9SJohnathan Mantey                 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
108049c53ac9SJohnathan Mantey                 if (odata == sensorJson.end())
108149c53ac9SJohnathan Mantey                 {
108249c53ac9SJohnathan Mantey                     continue;
108349c53ac9SJohnathan Mantey                 }
108449c53ac9SJohnathan Mantey                 std::string* value = odata->get_ptr<std::string*>();
108549c53ac9SJohnathan Mantey                 if (value != nullptr)
108649c53ac9SJohnathan Mantey                 {
108749c53ac9SJohnathan Mantey                     *value += std::to_string(count);
108849c53ac9SJohnathan Mantey                     count++;
108949c53ac9SJohnathan Mantey                 }
109049c53ac9SJohnathan Mantey             }
109149c53ac9SJohnathan Mantey         }
109249c53ac9SJohnathan Mantey     }
109349c53ac9SJohnathan Mantey }
109449c53ac9SJohnathan Mantey 
109508777fb0SLewanczyk, Dawid /**
1096adc4f0dbSShawn McCarney  * @brief Finds the inventory item with the specified object path.
1097adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
1098adc4f0dbSShawn McCarney  * @param invItemObjPath D-Bus object path of inventory item.
1099adc4f0dbSShawn McCarney  * @return Inventory item within vector, or nullptr if no match found.
11008fb49dd6SShawn McCarney  */
1101adc4f0dbSShawn McCarney static InventoryItem* findInventoryItem(
1102adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1103adc4f0dbSShawn McCarney     const std::string& invItemObjPath)
11048fb49dd6SShawn McCarney {
1105adc4f0dbSShawn McCarney     for (InventoryItem& inventoryItem : *inventoryItems)
11068fb49dd6SShawn McCarney     {
1107adc4f0dbSShawn McCarney         if (inventoryItem.objectPath == invItemObjPath)
11088fb49dd6SShawn McCarney         {
1109adc4f0dbSShawn McCarney             return &inventoryItem;
11108fb49dd6SShawn McCarney         }
11118fb49dd6SShawn McCarney     }
11128fb49dd6SShawn McCarney     return nullptr;
11138fb49dd6SShawn McCarney }
11148fb49dd6SShawn McCarney 
11158fb49dd6SShawn McCarney /**
1116adc4f0dbSShawn McCarney  * @brief Finds the inventory item associated with the specified sensor.
1117adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
1118adc4f0dbSShawn McCarney  * @param sensorObjPath D-Bus object path of sensor.
1119adc4f0dbSShawn McCarney  * @return Inventory item within vector, or nullptr if no match found.
11208fb49dd6SShawn McCarney  */
1121adc4f0dbSShawn McCarney static InventoryItem* findInventoryItemForSensor(
1122adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1123adc4f0dbSShawn McCarney     const std::string& sensorObjPath)
1124adc4f0dbSShawn McCarney {
1125adc4f0dbSShawn McCarney     for (InventoryItem& inventoryItem : *inventoryItems)
1126adc4f0dbSShawn McCarney     {
1127adc4f0dbSShawn McCarney         if (inventoryItem.sensors.count(sensorObjPath) > 0)
1128adc4f0dbSShawn McCarney         {
1129adc4f0dbSShawn McCarney             return &inventoryItem;
1130adc4f0dbSShawn McCarney         }
1131adc4f0dbSShawn McCarney     }
1132adc4f0dbSShawn McCarney     return nullptr;
1133adc4f0dbSShawn McCarney }
1134adc4f0dbSShawn McCarney 
1135adc4f0dbSShawn McCarney /**
1136adc4f0dbSShawn McCarney  * @brief Adds inventory item and associated sensor to specified vector.
1137adc4f0dbSShawn McCarney  *
1138adc4f0dbSShawn McCarney  * Adds a new InventoryItem to the vector if necessary.  Searches for an
1139adc4f0dbSShawn McCarney  * existing InventoryItem with the specified object path.  If not found, one is
1140adc4f0dbSShawn McCarney  * added to the vector.
1141adc4f0dbSShawn McCarney  *
1142adc4f0dbSShawn McCarney  * Next, the specified sensor is added to the set of sensors associated with the
1143adc4f0dbSShawn McCarney  * InventoryItem.
1144adc4f0dbSShawn McCarney  *
1145adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
1146adc4f0dbSShawn McCarney  * @param invItemObjPath D-Bus object path of inventory item.
1147adc4f0dbSShawn McCarney  * @param sensorObjPath D-Bus object path of sensor
1148adc4f0dbSShawn McCarney  */
1149adc4f0dbSShawn McCarney static void
1150adc4f0dbSShawn McCarney     addInventoryItem(std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1151adc4f0dbSShawn McCarney                      const std::string& invItemObjPath,
1152adc4f0dbSShawn McCarney                      const std::string& sensorObjPath)
1153adc4f0dbSShawn McCarney {
1154adc4f0dbSShawn McCarney     // Look for inventory item in vector
1155adc4f0dbSShawn McCarney     InventoryItem* inventoryItem =
1156adc4f0dbSShawn McCarney         findInventoryItem(inventoryItems, invItemObjPath);
1157adc4f0dbSShawn McCarney 
1158adc4f0dbSShawn McCarney     // If inventory item doesn't exist in vector, add it
1159adc4f0dbSShawn McCarney     if (inventoryItem == nullptr)
1160adc4f0dbSShawn McCarney     {
1161adc4f0dbSShawn McCarney         inventoryItems->emplace_back(invItemObjPath);
1162adc4f0dbSShawn McCarney         inventoryItem = &(inventoryItems->back());
1163adc4f0dbSShawn McCarney     }
1164adc4f0dbSShawn McCarney 
1165adc4f0dbSShawn McCarney     // Add sensor to set of sensors associated with inventory item
1166adc4f0dbSShawn McCarney     inventoryItem->sensors.emplace(sensorObjPath);
1167adc4f0dbSShawn McCarney }
1168adc4f0dbSShawn McCarney 
1169adc4f0dbSShawn McCarney /**
1170adc4f0dbSShawn McCarney  * @brief Stores D-Bus data in the specified inventory item.
1171adc4f0dbSShawn McCarney  *
1172adc4f0dbSShawn McCarney  * Finds D-Bus data in the specified map of interfaces.  Stores the data in the
1173adc4f0dbSShawn McCarney  * specified InventoryItem.
1174adc4f0dbSShawn McCarney  *
1175adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
1176adc4f0dbSShawn McCarney  * response.
1177adc4f0dbSShawn McCarney  *
1178adc4f0dbSShawn McCarney  * @param inventoryItem Inventory item where data will be stored.
1179adc4f0dbSShawn McCarney  * @param interfacesDict Map containing D-Bus interfaces and their properties
1180adc4f0dbSShawn McCarney  * for the specified inventory item.
1181adc4f0dbSShawn McCarney  */
1182adc4f0dbSShawn McCarney static void storeInventoryItemData(
1183adc4f0dbSShawn McCarney     InventoryItem& inventoryItem,
11848fb49dd6SShawn McCarney     const boost::container::flat_map<
11858fb49dd6SShawn McCarney         std::string, boost::container::flat_map<std::string, SensorVariant>>&
11868fb49dd6SShawn McCarney         interfacesDict)
11878fb49dd6SShawn McCarney {
1188adc4f0dbSShawn McCarney     // Get properties from Inventory.Item interface
1189adc4f0dbSShawn McCarney     auto interfaceIt =
1190adc4f0dbSShawn McCarney         interfacesDict.find("xyz.openbmc_project.Inventory.Item");
1191adc4f0dbSShawn McCarney     if (interfaceIt != interfacesDict.end())
11928fb49dd6SShawn McCarney     {
1193adc4f0dbSShawn McCarney         auto propertyIt = interfaceIt->second.find("Present");
1194adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
11958fb49dd6SShawn McCarney         {
1196adc4f0dbSShawn McCarney             const bool* value = std::get_if<bool>(&propertyIt->second);
1197adc4f0dbSShawn McCarney             if (value != nullptr)
11988fb49dd6SShawn McCarney             {
1199adc4f0dbSShawn McCarney                 inventoryItem.isPresent = *value;
12008fb49dd6SShawn McCarney             }
12018fb49dd6SShawn McCarney         }
12028fb49dd6SShawn McCarney     }
12038fb49dd6SShawn McCarney 
1204adc4f0dbSShawn McCarney     // Check if Inventory.Item.PowerSupply interface is present
1205adc4f0dbSShawn McCarney     interfaceIt =
1206adc4f0dbSShawn McCarney         interfacesDict.find("xyz.openbmc_project.Inventory.Item.PowerSupply");
1207adc4f0dbSShawn McCarney     if (interfaceIt != interfacesDict.end())
12088fb49dd6SShawn McCarney     {
1209adc4f0dbSShawn McCarney         inventoryItem.isPowerSupply = true;
12108fb49dd6SShawn McCarney     }
1211adc4f0dbSShawn McCarney 
1212adc4f0dbSShawn McCarney     // Get properties from Inventory.Decorator.Asset interface
1213adc4f0dbSShawn McCarney     interfaceIt =
1214adc4f0dbSShawn McCarney         interfacesDict.find("xyz.openbmc_project.Inventory.Decorator.Asset");
1215adc4f0dbSShawn McCarney     if (interfaceIt != interfacesDict.end())
1216adc4f0dbSShawn McCarney     {
1217adc4f0dbSShawn McCarney         auto propertyIt = interfaceIt->second.find("Manufacturer");
1218adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1219adc4f0dbSShawn McCarney         {
1220adc4f0dbSShawn McCarney             const std::string* value =
1221adc4f0dbSShawn McCarney                 std::get_if<std::string>(&propertyIt->second);
1222adc4f0dbSShawn McCarney             if (value != nullptr)
1223adc4f0dbSShawn McCarney             {
1224adc4f0dbSShawn McCarney                 inventoryItem.manufacturer = *value;
1225adc4f0dbSShawn McCarney             }
1226adc4f0dbSShawn McCarney         }
1227adc4f0dbSShawn McCarney 
1228adc4f0dbSShawn McCarney         propertyIt = interfaceIt->second.find("Model");
1229adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1230adc4f0dbSShawn McCarney         {
1231adc4f0dbSShawn McCarney             const std::string* value =
1232adc4f0dbSShawn McCarney                 std::get_if<std::string>(&propertyIt->second);
1233adc4f0dbSShawn McCarney             if (value != nullptr)
1234adc4f0dbSShawn McCarney             {
1235adc4f0dbSShawn McCarney                 inventoryItem.model = *value;
1236adc4f0dbSShawn McCarney             }
1237adc4f0dbSShawn McCarney         }
1238adc4f0dbSShawn McCarney 
1239adc4f0dbSShawn McCarney         propertyIt = interfaceIt->second.find("PartNumber");
1240adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1241adc4f0dbSShawn McCarney         {
1242adc4f0dbSShawn McCarney             const std::string* value =
1243adc4f0dbSShawn McCarney                 std::get_if<std::string>(&propertyIt->second);
1244adc4f0dbSShawn McCarney             if (value != nullptr)
1245adc4f0dbSShawn McCarney             {
1246adc4f0dbSShawn McCarney                 inventoryItem.partNumber = *value;
1247adc4f0dbSShawn McCarney             }
1248adc4f0dbSShawn McCarney         }
1249adc4f0dbSShawn McCarney 
1250adc4f0dbSShawn McCarney         propertyIt = interfaceIt->second.find("SerialNumber");
1251adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1252adc4f0dbSShawn McCarney         {
1253adc4f0dbSShawn McCarney             const std::string* value =
1254adc4f0dbSShawn McCarney                 std::get_if<std::string>(&propertyIt->second);
1255adc4f0dbSShawn McCarney             if (value != nullptr)
1256adc4f0dbSShawn McCarney             {
1257adc4f0dbSShawn McCarney                 inventoryItem.serialNumber = *value;
1258adc4f0dbSShawn McCarney             }
1259adc4f0dbSShawn McCarney         }
1260adc4f0dbSShawn McCarney     }
1261adc4f0dbSShawn McCarney 
1262adc4f0dbSShawn McCarney     // Get properties from State.Decorator.OperationalStatus interface
1263adc4f0dbSShawn McCarney     interfaceIt = interfacesDict.find(
1264adc4f0dbSShawn McCarney         "xyz.openbmc_project.State.Decorator.OperationalStatus");
1265adc4f0dbSShawn McCarney     if (interfaceIt != interfacesDict.end())
1266adc4f0dbSShawn McCarney     {
1267adc4f0dbSShawn McCarney         auto propertyIt = interfaceIt->second.find("Functional");
1268adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1269adc4f0dbSShawn McCarney         {
1270adc4f0dbSShawn McCarney             const bool* value = std::get_if<bool>(&propertyIt->second);
1271adc4f0dbSShawn McCarney             if (value != nullptr)
1272adc4f0dbSShawn McCarney             {
1273adc4f0dbSShawn McCarney                 inventoryItem.isFunctional = *value;
12748fb49dd6SShawn McCarney             }
12758fb49dd6SShawn McCarney         }
12768fb49dd6SShawn McCarney     }
12778fb49dd6SShawn McCarney }
12788fb49dd6SShawn McCarney 
12798fb49dd6SShawn McCarney /**
1280adc4f0dbSShawn McCarney  * @brief Gets D-Bus data for inventory items associated with sensors.
12818fb49dd6SShawn McCarney  *
1282adc4f0dbSShawn McCarney  * Uses the specified connections (services) to obtain D-Bus data for inventory
1283adc4f0dbSShawn McCarney  * items associated with sensors.  Stores the resulting data in the
1284adc4f0dbSShawn McCarney  * inventoryItems vector.
12858fb49dd6SShawn McCarney  *
1286adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
1287adc4f0dbSShawn McCarney  * response.
1288adc4f0dbSShawn McCarney  *
1289adc4f0dbSShawn McCarney  * Finds the inventory item data asynchronously.  Invokes callback when data has
1290adc4f0dbSShawn McCarney  * been obtained.
1291adc4f0dbSShawn McCarney  *
1292adc4f0dbSShawn McCarney  * The callback must have the following signature:
1293adc4f0dbSShawn McCarney  *   @code
1294adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1295adc4f0dbSShawn McCarney  *   @endcode
1296adc4f0dbSShawn McCarney  *
1297adc4f0dbSShawn McCarney  * This function is called recursively, obtaining data asynchronously from one
1298adc4f0dbSShawn McCarney  * connection in each call.  This ensures the callback is not invoked until the
1299adc4f0dbSShawn McCarney  * last asynchronous function has completed.
13008fb49dd6SShawn McCarney  *
13018fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
1302adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
1303adc4f0dbSShawn McCarney  * @param invConnections Connections that provide data for the inventory items.
13048fb49dd6SShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
13058fb49dd6SShawn McCarney  * implements ObjectManager.
1306adc4f0dbSShawn McCarney  * @param callback Callback to invoke when inventory data has been obtained.
1307adc4f0dbSShawn McCarney  * @param invConnectionsIndex Current index in invConnections.  Only specified
1308adc4f0dbSShawn McCarney  * in recursive calls to this function.
13098fb49dd6SShawn McCarney  */
1310adc4f0dbSShawn McCarney template <typename Callback>
1311adc4f0dbSShawn McCarney static void getInventoryItemsData(
13128fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1313adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
13148fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_set<std::string>> invConnections,
13158fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1316adc4f0dbSShawn McCarney         objectMgrPaths,
1317*271584abSEd Tanous     Callback&& callback, size_t invConnectionsIndex = 0)
13188fb49dd6SShawn McCarney {
1319adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsData enter";
13208fb49dd6SShawn McCarney 
1321adc4f0dbSShawn McCarney     // If no more connections left, call callback
1322adc4f0dbSShawn McCarney     if (invConnectionsIndex >= invConnections->size())
13238fb49dd6SShawn McCarney     {
1324adc4f0dbSShawn McCarney         callback(inventoryItems);
1325adc4f0dbSShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemsData exit";
1326adc4f0dbSShawn McCarney         return;
1327adc4f0dbSShawn McCarney     }
1328adc4f0dbSShawn McCarney 
1329adc4f0dbSShawn McCarney     // Get inventory item data from current connection
1330adc4f0dbSShawn McCarney     auto it = invConnections->nth(invConnectionsIndex);
1331adc4f0dbSShawn McCarney     if (it != invConnections->end())
1332adc4f0dbSShawn McCarney     {
1333adc4f0dbSShawn McCarney         const std::string& invConnection = *it;
1334adc4f0dbSShawn McCarney 
13358fb49dd6SShawn McCarney         // Response handler for GetManagedObjects
1336adc4f0dbSShawn McCarney         auto respHandler = [sensorsAsyncResp, inventoryItems, invConnections,
1337adc4f0dbSShawn McCarney                             objectMgrPaths, callback{std::move(callback)},
1338adc4f0dbSShawn McCarney                             invConnectionsIndex](
1339adc4f0dbSShawn McCarney                                const boost::system::error_code ec,
13408fb49dd6SShawn McCarney                                ManagedObjectsVectorType& resp) {
1341adc4f0dbSShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemsData respHandler enter";
13428fb49dd6SShawn McCarney             if (ec)
13438fb49dd6SShawn McCarney             {
13448fb49dd6SShawn McCarney                 BMCWEB_LOG_ERROR
1345adc4f0dbSShawn McCarney                     << "getInventoryItemsData respHandler DBus error " << ec;
13468fb49dd6SShawn McCarney                 messages::internalError(sensorsAsyncResp->res);
13478fb49dd6SShawn McCarney                 return;
13488fb49dd6SShawn McCarney             }
13498fb49dd6SShawn McCarney 
13508fb49dd6SShawn McCarney             // Loop through returned object paths
13518fb49dd6SShawn McCarney             for (const auto& objDictEntry : resp)
13528fb49dd6SShawn McCarney             {
13538fb49dd6SShawn McCarney                 const std::string& objPath =
13548fb49dd6SShawn McCarney                     static_cast<const std::string&>(objDictEntry.first);
13558fb49dd6SShawn McCarney 
1356adc4f0dbSShawn McCarney                 // If this object path is one of the specified inventory items
1357adc4f0dbSShawn McCarney                 InventoryItem* inventoryItem =
1358adc4f0dbSShawn McCarney                     findInventoryItem(inventoryItems, objPath);
1359adc4f0dbSShawn McCarney                 if (inventoryItem != nullptr)
13608fb49dd6SShawn McCarney                 {
1361adc4f0dbSShawn McCarney                     // Store inventory data in InventoryItem
1362adc4f0dbSShawn McCarney                     storeInventoryItemData(*inventoryItem, objDictEntry.second);
13638fb49dd6SShawn McCarney                 }
13648fb49dd6SShawn McCarney             }
13658fb49dd6SShawn McCarney 
1366adc4f0dbSShawn McCarney             // Recurse to get inventory item data from next connection
1367adc4f0dbSShawn McCarney             getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1368adc4f0dbSShawn McCarney                                   invConnections, objectMgrPaths,
1369adc4f0dbSShawn McCarney                                   std::move(callback), invConnectionsIndex + 1);
1370adc4f0dbSShawn McCarney 
1371adc4f0dbSShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemsData respHandler exit";
13728fb49dd6SShawn McCarney         };
13738fb49dd6SShawn McCarney 
13748fb49dd6SShawn McCarney         // Find DBus object path that implements ObjectManager for the current
13758fb49dd6SShawn McCarney         // connection.  If no mapping found, default to "/".
13768fb49dd6SShawn McCarney         auto iter = objectMgrPaths->find(invConnection);
13778fb49dd6SShawn McCarney         const std::string& objectMgrPath =
13788fb49dd6SShawn McCarney             (iter != objectMgrPaths->end()) ? iter->second : "/";
13798fb49dd6SShawn McCarney         BMCWEB_LOG_DEBUG << "ObjectManager path for " << invConnection << " is "
13808fb49dd6SShawn McCarney                          << objectMgrPath;
13818fb49dd6SShawn McCarney 
13828fb49dd6SShawn McCarney         // Get all object paths and their interfaces for current connection
13838fb49dd6SShawn McCarney         crow::connections::systemBus->async_method_call(
13848fb49dd6SShawn McCarney             std::move(respHandler), invConnection, objectMgrPath,
13858fb49dd6SShawn McCarney             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
13868fb49dd6SShawn McCarney     }
13878fb49dd6SShawn McCarney 
1388adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsData exit";
13898fb49dd6SShawn McCarney }
13908fb49dd6SShawn McCarney 
13918fb49dd6SShawn McCarney /**
1392adc4f0dbSShawn McCarney  * @brief Gets connections that provide D-Bus data for inventory items.
13938fb49dd6SShawn McCarney  *
1394adc4f0dbSShawn McCarney  * Gets the D-Bus connections (services) that provide data for the inventory
1395adc4f0dbSShawn McCarney  * items that are associated with sensors.
13968fb49dd6SShawn McCarney  *
13978fb49dd6SShawn McCarney  * Finds the connections asynchronously.  Invokes callback when information has
13988fb49dd6SShawn McCarney  * been obtained.
13998fb49dd6SShawn McCarney  *
14008fb49dd6SShawn McCarney  * The callback must have the following signature:
14018fb49dd6SShawn McCarney  *   @code
14028fb49dd6SShawn McCarney  *   callback(std::shared_ptr<boost::container::flat_set<std::string>>
14038fb49dd6SShawn McCarney  *            invConnections)
14048fb49dd6SShawn McCarney  *   @endcode
14058fb49dd6SShawn McCarney  *
14068fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
1407adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
14088fb49dd6SShawn McCarney  * @param callback Callback to invoke when connections have been obtained.
14098fb49dd6SShawn McCarney  */
14108fb49dd6SShawn McCarney template <typename Callback>
14118fb49dd6SShawn McCarney static void getInventoryItemsConnections(
14128fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1413adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
14148fb49dd6SShawn McCarney     Callback&& callback)
14158fb49dd6SShawn McCarney {
14168fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsConnections enter";
14178fb49dd6SShawn McCarney 
14188fb49dd6SShawn McCarney     const std::string path = "/xyz/openbmc_project/inventory";
1419adc4f0dbSShawn McCarney     const std::array<std::string, 4> interfaces = {
14208fb49dd6SShawn McCarney         "xyz.openbmc_project.Inventory.Item",
1421adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Item.PowerSupply",
1422adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Decorator.Asset",
14238fb49dd6SShawn McCarney         "xyz.openbmc_project.State.Decorator.OperationalStatus"};
14248fb49dd6SShawn McCarney 
14258fb49dd6SShawn McCarney     // Response handler for parsing output from GetSubTree
14268fb49dd6SShawn McCarney     auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
1427adc4f0dbSShawn McCarney                         inventoryItems](const boost::system::error_code ec,
14288fb49dd6SShawn McCarney                                         const GetSubTreeType& subtree) {
14298fb49dd6SShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler enter";
14308fb49dd6SShawn McCarney         if (ec)
14318fb49dd6SShawn McCarney         {
14328fb49dd6SShawn McCarney             messages::internalError(sensorsAsyncResp->res);
14338fb49dd6SShawn McCarney             BMCWEB_LOG_ERROR
14348fb49dd6SShawn McCarney                 << "getInventoryItemsConnections respHandler DBus error " << ec;
14358fb49dd6SShawn McCarney             return;
14368fb49dd6SShawn McCarney         }
14378fb49dd6SShawn McCarney 
14388fb49dd6SShawn McCarney         // Make unique list of connections for desired inventory items
14398fb49dd6SShawn McCarney         std::shared_ptr<boost::container::flat_set<std::string>>
14408fb49dd6SShawn McCarney             invConnections =
14418fb49dd6SShawn McCarney                 std::make_shared<boost::container::flat_set<std::string>>();
14428fb49dd6SShawn McCarney         invConnections->reserve(8);
14438fb49dd6SShawn McCarney 
14448fb49dd6SShawn McCarney         // Loop through objects from GetSubTree
14458fb49dd6SShawn McCarney         for (const std::pair<
14468fb49dd6SShawn McCarney                  std::string,
14478fb49dd6SShawn McCarney                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
14488fb49dd6SShawn McCarney                  object : subtree)
14498fb49dd6SShawn McCarney         {
1450adc4f0dbSShawn McCarney             // Check if object path is one of the specified inventory items
14518fb49dd6SShawn McCarney             const std::string& objPath = object.first;
1452adc4f0dbSShawn McCarney             if (findInventoryItem(inventoryItems, objPath) != nullptr)
14538fb49dd6SShawn McCarney             {
14548fb49dd6SShawn McCarney                 // Store all connections to inventory item
14558fb49dd6SShawn McCarney                 for (const std::pair<std::string, std::vector<std::string>>&
14568fb49dd6SShawn McCarney                          objData : object.second)
14578fb49dd6SShawn McCarney                 {
14588fb49dd6SShawn McCarney                     const std::string& invConnection = objData.first;
14598fb49dd6SShawn McCarney                     invConnections->insert(invConnection);
14608fb49dd6SShawn McCarney                 }
14618fb49dd6SShawn McCarney             }
14628fb49dd6SShawn McCarney         }
14638fb49dd6SShawn McCarney         callback(invConnections);
14648fb49dd6SShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler exit";
14658fb49dd6SShawn McCarney     };
14668fb49dd6SShawn McCarney 
14678fb49dd6SShawn McCarney     // Make call to ObjectMapper to find all inventory items
14688fb49dd6SShawn McCarney     crow::connections::systemBus->async_method_call(
14698fb49dd6SShawn McCarney         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
14708fb49dd6SShawn McCarney         "/xyz/openbmc_project/object_mapper",
14718fb49dd6SShawn McCarney         "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 0, interfaces);
14728fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsConnections exit";
14738fb49dd6SShawn McCarney }
14748fb49dd6SShawn McCarney 
14758fb49dd6SShawn McCarney /**
1476adc4f0dbSShawn McCarney  * @brief Gets associations from sensors to inventory items.
14778fb49dd6SShawn McCarney  *
14788fb49dd6SShawn McCarney  * Looks for ObjectMapper associations from the specified sensors to related
1479adc4f0dbSShawn McCarney  * inventory items.
14808fb49dd6SShawn McCarney  *
14818fb49dd6SShawn McCarney  * Finds the inventory items asynchronously.  Invokes callback when information
14828fb49dd6SShawn McCarney  * has been obtained.
14838fb49dd6SShawn McCarney  *
14848fb49dd6SShawn McCarney  * The callback must have the following signature:
14858fb49dd6SShawn McCarney  *   @code
1486adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
14878fb49dd6SShawn McCarney  *   @endcode
14888fb49dd6SShawn McCarney  *
14898fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
14908fb49dd6SShawn McCarney  * @param sensorNames All sensors within the current chassis.
14918fb49dd6SShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
14928fb49dd6SShawn McCarney  * implements ObjectManager.
14938fb49dd6SShawn McCarney  * @param callback Callback to invoke when inventory items have been obtained.
14948fb49dd6SShawn McCarney  */
14958fb49dd6SShawn McCarney template <typename Callback>
1496adc4f0dbSShawn McCarney static void getInventoryItemAssociations(
14978fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
14988fb49dd6SShawn McCarney     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
14998fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
15008fb49dd6SShawn McCarney         objectMgrPaths,
15018fb49dd6SShawn McCarney     Callback&& callback)
15028fb49dd6SShawn McCarney {
1503adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemAssociations enter";
15048fb49dd6SShawn McCarney 
15058fb49dd6SShawn McCarney     // Response handler for GetManagedObjects
15068fb49dd6SShawn McCarney     auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
15078fb49dd6SShawn McCarney                         sensorNames](const boost::system::error_code ec,
15088fb49dd6SShawn McCarney                                      dbus::utility::ManagedObjectType& resp) {
1509adc4f0dbSShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemAssociations respHandler enter";
15108fb49dd6SShawn McCarney         if (ec)
15118fb49dd6SShawn McCarney         {
1512adc4f0dbSShawn McCarney             BMCWEB_LOG_ERROR
1513adc4f0dbSShawn McCarney                 << "getInventoryItemAssociations respHandler DBus error " << ec;
15148fb49dd6SShawn McCarney             messages::internalError(sensorsAsyncResp->res);
15158fb49dd6SShawn McCarney             return;
15168fb49dd6SShawn McCarney         }
15178fb49dd6SShawn McCarney 
1518adc4f0dbSShawn McCarney         // Create vector to hold list of inventory items
1519adc4f0dbSShawn McCarney         std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1520adc4f0dbSShawn McCarney             std::make_shared<std::vector<InventoryItem>>();
1521adc4f0dbSShawn McCarney 
15228fb49dd6SShawn McCarney         // Loop through returned object paths
15238fb49dd6SShawn McCarney         std::string sensorAssocPath;
15248fb49dd6SShawn McCarney         sensorAssocPath.reserve(128); // avoid memory allocations
15258fb49dd6SShawn McCarney         for (const auto& objDictEntry : resp)
15268fb49dd6SShawn McCarney         {
15278fb49dd6SShawn McCarney             const std::string& objPath =
15288fb49dd6SShawn McCarney                 static_cast<const std::string&>(objDictEntry.first);
15298fb49dd6SShawn McCarney             const boost::container::flat_map<
15308fb49dd6SShawn McCarney                 std::string, boost::container::flat_map<
15318fb49dd6SShawn McCarney                                  std::string, dbus::utility::DbusVariantType>>&
15328fb49dd6SShawn McCarney                 interfacesDict = objDictEntry.second;
15338fb49dd6SShawn McCarney 
15348fb49dd6SShawn McCarney             // If path is inventory association for one of the specified sensors
15358fb49dd6SShawn McCarney             for (const std::string& sensorName : *sensorNames)
15368fb49dd6SShawn McCarney             {
15378fb49dd6SShawn McCarney                 sensorAssocPath = sensorName;
15388fb49dd6SShawn McCarney                 sensorAssocPath += "/inventory";
15398fb49dd6SShawn McCarney                 if (objPath == sensorAssocPath)
15408fb49dd6SShawn McCarney                 {
15418fb49dd6SShawn McCarney                     // Get Association interface for object path
15428fb49dd6SShawn McCarney                     auto assocIt =
15438fb49dd6SShawn McCarney                         interfacesDict.find("xyz.openbmc_project.Association");
15448fb49dd6SShawn McCarney                     if (assocIt != interfacesDict.end())
15458fb49dd6SShawn McCarney                     {
15468fb49dd6SShawn McCarney                         // Get inventory item from end point
15478fb49dd6SShawn McCarney                         auto endpointsIt = assocIt->second.find("endpoints");
15488fb49dd6SShawn McCarney                         if (endpointsIt != assocIt->second.end())
15498fb49dd6SShawn McCarney                         {
15508fb49dd6SShawn McCarney                             const std::vector<std::string>* endpoints =
15518fb49dd6SShawn McCarney                                 std::get_if<std::vector<std::string>>(
15528fb49dd6SShawn McCarney                                     &endpointsIt->second);
15538fb49dd6SShawn McCarney                             if ((endpoints != nullptr) && !endpoints->empty())
15548fb49dd6SShawn McCarney                             {
1555adc4f0dbSShawn McCarney                                 // Add inventory item to vector
1556adc4f0dbSShawn McCarney                                 const std::string& invItemPath =
1557adc4f0dbSShawn McCarney                                     endpoints->front();
1558adc4f0dbSShawn McCarney                                 addInventoryItem(inventoryItems, invItemPath,
1559adc4f0dbSShawn McCarney                                                  sensorName);
15608fb49dd6SShawn McCarney                             }
15618fb49dd6SShawn McCarney                         }
15628fb49dd6SShawn McCarney                     }
15638fb49dd6SShawn McCarney                     break;
15648fb49dd6SShawn McCarney                 }
15658fb49dd6SShawn McCarney             }
15668fb49dd6SShawn McCarney         }
15678fb49dd6SShawn McCarney 
1568adc4f0dbSShawn McCarney         callback(inventoryItems);
1569adc4f0dbSShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemAssociations respHandler exit";
15708fb49dd6SShawn McCarney     };
15718fb49dd6SShawn McCarney 
15728fb49dd6SShawn McCarney     // Find DBus object path that implements ObjectManager for ObjectMapper
15738fb49dd6SShawn McCarney     std::string connection = "xyz.openbmc_project.ObjectMapper";
15748fb49dd6SShawn McCarney     auto iter = objectMgrPaths->find(connection);
15758fb49dd6SShawn McCarney     const std::string& objectMgrPath =
15768fb49dd6SShawn McCarney         (iter != objectMgrPaths->end()) ? iter->second : "/";
15778fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
15788fb49dd6SShawn McCarney                      << objectMgrPath;
15798fb49dd6SShawn McCarney 
15808fb49dd6SShawn McCarney     // Call GetManagedObjects on the ObjectMapper to get all associations
15818fb49dd6SShawn McCarney     crow::connections::systemBus->async_method_call(
15828fb49dd6SShawn McCarney         std::move(respHandler), connection, objectMgrPath,
15838fb49dd6SShawn McCarney         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
15848fb49dd6SShawn McCarney 
1585adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemAssociations exit";
15868fb49dd6SShawn McCarney }
15878fb49dd6SShawn McCarney 
15888fb49dd6SShawn McCarney /**
1589adc4f0dbSShawn McCarney  * @brief Gets inventory items associated with sensors.
15908fb49dd6SShawn McCarney  *
15918fb49dd6SShawn McCarney  * Finds the inventory items that are associated with the specified sensors.
1592adc4f0dbSShawn McCarney  * Then gets D-Bus data for the inventory items, such as presence and VPD.
15938fb49dd6SShawn McCarney  *
1594adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
1595adc4f0dbSShawn McCarney  * response.
15968fb49dd6SShawn McCarney  *
1597adc4f0dbSShawn McCarney  * Finds the inventory items asynchronously.  Invokes callback when the
1598adc4f0dbSShawn McCarney  * inventory items have been obtained.
1599adc4f0dbSShawn McCarney  *
1600adc4f0dbSShawn McCarney  * The callback must have the following signature:
1601adc4f0dbSShawn McCarney  *   @code
1602adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1603adc4f0dbSShawn McCarney  *   @endcode
16048fb49dd6SShawn McCarney  *
16058fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
16068fb49dd6SShawn McCarney  * @param sensorNames All sensors within the current chassis.
16078fb49dd6SShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
16088fb49dd6SShawn McCarney  * implements ObjectManager.
1609adc4f0dbSShawn McCarney  * @param callback Callback to invoke when inventory items have been obtained.
16108fb49dd6SShawn McCarney  */
1611adc4f0dbSShawn McCarney template <typename Callback>
1612adc4f0dbSShawn McCarney static void getInventoryItems(
16138fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
16148fb49dd6SShawn McCarney     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
16158fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1616adc4f0dbSShawn McCarney         objectMgrPaths,
1617adc4f0dbSShawn McCarney     Callback&& callback)
16188fb49dd6SShawn McCarney {
1619adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItems enter";
1620adc4f0dbSShawn McCarney     auto getInventoryItemAssociationsCb =
1621adc4f0dbSShawn McCarney         [sensorsAsyncResp, objectMgrPaths, callback{std::move(callback)}](
1622adc4f0dbSShawn McCarney             std::shared_ptr<std::vector<InventoryItem>> inventoryItems) {
1623adc4f0dbSShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemAssociationsCb enter";
16248fb49dd6SShawn McCarney             auto getInventoryItemsConnectionsCb =
1625adc4f0dbSShawn McCarney                 [sensorsAsyncResp, inventoryItems, objectMgrPaths,
1626adc4f0dbSShawn McCarney                  callback{std::move(callback)}](
16278fb49dd6SShawn McCarney                     std::shared_ptr<boost::container::flat_set<std::string>>
16288fb49dd6SShawn McCarney                         invConnections) {
16298fb49dd6SShawn McCarney                     BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb enter";
16308fb49dd6SShawn McCarney 
1631adc4f0dbSShawn McCarney                     // Get inventory item data from connections
1632adc4f0dbSShawn McCarney                     getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1633adc4f0dbSShawn McCarney                                           invConnections, objectMgrPaths,
1634adc4f0dbSShawn McCarney                                           std::move(callback));
16358fb49dd6SShawn McCarney 
16368fb49dd6SShawn McCarney                     BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb exit";
16378fb49dd6SShawn McCarney                 };
16388fb49dd6SShawn McCarney 
1639adc4f0dbSShawn McCarney             // Get connections that provide inventory item data
16408fb49dd6SShawn McCarney             getInventoryItemsConnections(
1641adc4f0dbSShawn McCarney                 sensorsAsyncResp, inventoryItems,
16428fb49dd6SShawn McCarney                 std::move(getInventoryItemsConnectionsCb));
1643adc4f0dbSShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemAssociationsCb exit";
16448fb49dd6SShawn McCarney         };
16458fb49dd6SShawn McCarney 
1646adc4f0dbSShawn McCarney     // Get associations from sensors to inventory items
1647adc4f0dbSShawn McCarney     getInventoryItemAssociations(sensorsAsyncResp, sensorNames, objectMgrPaths,
1648adc4f0dbSShawn McCarney                                  std::move(getInventoryItemAssociationsCb));
1649adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItems exit";
1650adc4f0dbSShawn McCarney }
1651adc4f0dbSShawn McCarney 
1652adc4f0dbSShawn McCarney /**
1653adc4f0dbSShawn McCarney  * @brief Returns JSON PowerSupply object for the specified inventory item.
1654adc4f0dbSShawn McCarney  *
1655adc4f0dbSShawn McCarney  * Searches for a JSON PowerSupply object that matches the specified inventory
1656adc4f0dbSShawn McCarney  * item.  If one is not found, a new PowerSupply object is added to the JSON
1657adc4f0dbSShawn McCarney  * array.
1658adc4f0dbSShawn McCarney  *
1659adc4f0dbSShawn McCarney  * Multiple sensors are often associated with one power supply inventory item.
1660adc4f0dbSShawn McCarney  * As a result, multiple sensor values are stored in one JSON PowerSupply
1661adc4f0dbSShawn McCarney  * object.
1662adc4f0dbSShawn McCarney  *
1663adc4f0dbSShawn McCarney  * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1664adc4f0dbSShawn McCarney  * @param inventoryItem Inventory item for the power supply.
1665adc4f0dbSShawn McCarney  * @param chassisId Chassis that contains the power supply.
1666adc4f0dbSShawn McCarney  * @return JSON PowerSupply object for the specified inventory item.
1667adc4f0dbSShawn McCarney  */
1668adc4f0dbSShawn McCarney static nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
1669adc4f0dbSShawn McCarney                                       const InventoryItem& inventoryItem,
1670adc4f0dbSShawn McCarney                                       const std::string& chassisId)
1671adc4f0dbSShawn McCarney {
1672adc4f0dbSShawn McCarney     // Check if matching PowerSupply object already exists in JSON array
1673adc4f0dbSShawn McCarney     for (nlohmann::json& powerSupply : powerSupplyArray)
1674adc4f0dbSShawn McCarney     {
1675adc4f0dbSShawn McCarney         if (powerSupply["MemberId"] == inventoryItem.name)
1676adc4f0dbSShawn McCarney         {
1677adc4f0dbSShawn McCarney             return powerSupply;
1678adc4f0dbSShawn McCarney         }
1679adc4f0dbSShawn McCarney     }
1680adc4f0dbSShawn McCarney 
1681adc4f0dbSShawn McCarney     // Add new PowerSupply object to JSON array
1682adc4f0dbSShawn McCarney     powerSupplyArray.push_back({});
1683adc4f0dbSShawn McCarney     nlohmann::json& powerSupply = powerSupplyArray.back();
1684adc4f0dbSShawn McCarney     powerSupply["@odata.id"] =
1685adc4f0dbSShawn McCarney         "/redfish/v1/Chassis/" + chassisId + "/Power#/PowerSupplies/";
1686adc4f0dbSShawn McCarney     powerSupply["MemberId"] = inventoryItem.name;
1687adc4f0dbSShawn McCarney     powerSupply["Name"] = boost::replace_all_copy(inventoryItem.name, "_", " ");
1688adc4f0dbSShawn McCarney     powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1689adc4f0dbSShawn McCarney     powerSupply["Model"] = inventoryItem.model;
1690adc4f0dbSShawn McCarney     powerSupply["PartNumber"] = inventoryItem.partNumber;
1691adc4f0dbSShawn McCarney     powerSupply["SerialNumber"] = inventoryItem.serialNumber;
1692adc4f0dbSShawn McCarney     powerSupply["Status"]["State"] = getState(&inventoryItem);
1693adc4f0dbSShawn McCarney 
1694adc4f0dbSShawn McCarney     const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1695adc4f0dbSShawn McCarney     powerSupply["Status"]["Health"] = health;
1696adc4f0dbSShawn McCarney 
1697adc4f0dbSShawn McCarney     return powerSupply;
16988fb49dd6SShawn McCarney }
16998fb49dd6SShawn McCarney 
17008fb49dd6SShawn McCarney /**
1701de629b6eSShawn McCarney  * @brief Gets the values of the specified sensors.
1702de629b6eSShawn McCarney  *
1703de629b6eSShawn McCarney  * Stores the results as JSON in the SensorsAsyncResp.
1704de629b6eSShawn McCarney  *
1705de629b6eSShawn McCarney  * Gets the sensor values asynchronously.  Stores the results later when the
1706de629b6eSShawn McCarney  * information has been obtained.
1707de629b6eSShawn McCarney  *
1708adc4f0dbSShawn McCarney  * The sensorNames set contains all requested sensors for the current chassis.
1709de629b6eSShawn McCarney  *
1710de629b6eSShawn McCarney  * To minimize the number of DBus calls, the DBus method
1711de629b6eSShawn McCarney  * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1712de629b6eSShawn McCarney  * values of all sensors provided by a connection (service).
1713de629b6eSShawn McCarney  *
1714de629b6eSShawn McCarney  * The connections set contains all the connections that provide sensor values.
1715de629b6eSShawn McCarney  *
1716de629b6eSShawn McCarney  * The objectMgrPaths map contains mappings from a connection name to the
1717de629b6eSShawn McCarney  * corresponding DBus object path that implements ObjectManager.
1718de629b6eSShawn McCarney  *
1719adc4f0dbSShawn McCarney  * The InventoryItem vector contains D-Bus inventory items associated with the
1720adc4f0dbSShawn McCarney  * sensors.  Inventory item data is needed for some Redfish sensor properties.
1721adc4f0dbSShawn McCarney  *
1722de629b6eSShawn McCarney  * @param SensorsAsyncResp Pointer to object holding response data.
1723adc4f0dbSShawn McCarney  * @param sensorNames All requested sensors within the current chassis.
1724de629b6eSShawn McCarney  * @param connections Connections that provide sensor values.
1725de629b6eSShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
1726de629b6eSShawn McCarney  * implements ObjectManager.
1727adc4f0dbSShawn McCarney  * @param inventoryItems Inventory items associated with the sensors.
1728de629b6eSShawn McCarney  */
1729de629b6eSShawn McCarney void getSensorData(
1730de629b6eSShawn McCarney     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
173149c53ac9SJohnathan Mantey     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
1732de629b6eSShawn McCarney     const boost::container::flat_set<std::string>& connections,
17338fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1734adc4f0dbSShawn McCarney         objectMgrPaths,
1735adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1736de629b6eSShawn McCarney {
1737de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getSensorData enter";
1738de629b6eSShawn McCarney     // Get managed objects from all services exposing sensors
1739de629b6eSShawn McCarney     for (const std::string& connection : connections)
1740de629b6eSShawn McCarney     {
1741de629b6eSShawn McCarney         // Response handler to process managed objects
17428fb49dd6SShawn McCarney         auto getManagedObjectsCb = [SensorsAsyncResp, sensorNames,
1743adc4f0dbSShawn McCarney                                     inventoryItems](
1744de629b6eSShawn McCarney                                        const boost::system::error_code ec,
1745de629b6eSShawn McCarney                                        ManagedObjectsVectorType& resp) {
1746de629b6eSShawn McCarney             BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
1747de629b6eSShawn McCarney             if (ec)
1748de629b6eSShawn McCarney             {
1749de629b6eSShawn McCarney                 BMCWEB_LOG_ERROR << "getManagedObjectsCb DBUS error: " << ec;
1750de629b6eSShawn McCarney                 messages::internalError(SensorsAsyncResp->res);
1751de629b6eSShawn McCarney                 return;
1752de629b6eSShawn McCarney             }
1753de629b6eSShawn McCarney             // Go through all objects and update response with sensor data
1754de629b6eSShawn McCarney             for (const auto& objDictEntry : resp)
1755de629b6eSShawn McCarney             {
1756de629b6eSShawn McCarney                 const std::string& objPath =
1757de629b6eSShawn McCarney                     static_cast<const std::string&>(objDictEntry.first);
1758de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "getManagedObjectsCb parsing object "
1759de629b6eSShawn McCarney                                  << objPath;
1760de629b6eSShawn McCarney 
1761de629b6eSShawn McCarney                 std::vector<std::string> split;
1762de629b6eSShawn McCarney                 // Reserve space for
1763de629b6eSShawn McCarney                 // /xyz/openbmc_project/sensors/<name>/<subname>
1764de629b6eSShawn McCarney                 split.reserve(6);
1765de629b6eSShawn McCarney                 boost::algorithm::split(split, objPath, boost::is_any_of("/"));
1766de629b6eSShawn McCarney                 if (split.size() < 6)
1767de629b6eSShawn McCarney                 {
1768de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << "Got path that isn't long enough "
1769de629b6eSShawn McCarney                                      << objPath;
1770de629b6eSShawn McCarney                     continue;
1771de629b6eSShawn McCarney                 }
1772de629b6eSShawn McCarney                 // These indexes aren't intuitive, as boost::split puts an empty
1773de629b6eSShawn McCarney                 // string at the beginning
1774de629b6eSShawn McCarney                 const std::string& sensorType = split[4];
1775de629b6eSShawn McCarney                 const std::string& sensorName = split[5];
1776de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "sensorName " << sensorName
1777de629b6eSShawn McCarney                                  << " sensorType " << sensorType;
177849c53ac9SJohnathan Mantey                 if (sensorNames->find(objPath) == sensorNames->end())
1779de629b6eSShawn McCarney                 {
1780de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << sensorName << " not in sensor list ";
1781de629b6eSShawn McCarney                     continue;
1782de629b6eSShawn McCarney                 }
1783de629b6eSShawn McCarney 
1784adc4f0dbSShawn McCarney                 // Find inventory item (if any) associated with sensor
1785adc4f0dbSShawn McCarney                 InventoryItem* inventoryItem =
1786adc4f0dbSShawn McCarney                     findInventoryItemForSensor(inventoryItems, objPath);
1787adc4f0dbSShawn McCarney 
178895a3ecadSAnthony Wilson                 const std::string& sensorSchema =
178995a3ecadSAnthony Wilson                     SensorsAsyncResp->chassisSubNode;
179095a3ecadSAnthony Wilson 
179195a3ecadSAnthony Wilson                 nlohmann::json* sensorJson = nullptr;
179295a3ecadSAnthony Wilson 
179395a3ecadSAnthony Wilson                 if (sensorSchema == "Sensors")
179495a3ecadSAnthony Wilson                 {
179595a3ecadSAnthony Wilson                     SensorsAsyncResp->res.jsonValue["@odata.id"] =
179695a3ecadSAnthony Wilson                         "/redfish/v1/Chassis/" + SensorsAsyncResp->chassisId +
179795a3ecadSAnthony Wilson                         "/" + SensorsAsyncResp->chassisSubNode + "/" +
179895a3ecadSAnthony Wilson                         sensorName;
179995a3ecadSAnthony Wilson                     sensorJson = &(SensorsAsyncResp->res.jsonValue);
180095a3ecadSAnthony Wilson                 }
180195a3ecadSAnthony Wilson                 else
180295a3ecadSAnthony Wilson                 {
1803*271584abSEd Tanous                     std::string fieldName;
1804de629b6eSShawn McCarney                     if (sensorType == "temperature")
1805de629b6eSShawn McCarney                     {
1806de629b6eSShawn McCarney                         fieldName = "Temperatures";
1807de629b6eSShawn McCarney                     }
1808de629b6eSShawn McCarney                     else if (sensorType == "fan" || sensorType == "fan_tach" ||
1809de629b6eSShawn McCarney                              sensorType == "fan_pwm")
1810de629b6eSShawn McCarney                     {
1811de629b6eSShawn McCarney                         fieldName = "Fans";
1812de629b6eSShawn McCarney                     }
1813de629b6eSShawn McCarney                     else if (sensorType == "voltage")
1814de629b6eSShawn McCarney                     {
1815de629b6eSShawn McCarney                         fieldName = "Voltages";
1816de629b6eSShawn McCarney                     }
1817de629b6eSShawn McCarney                     else if (sensorType == "power")
1818de629b6eSShawn McCarney                     {
1819028f7ebcSEddie James                         if (!sensorName.compare("total_power"))
1820028f7ebcSEddie James                         {
1821028f7ebcSEddie James                             fieldName = "PowerControl";
1822028f7ebcSEddie James                         }
1823adc4f0dbSShawn McCarney                         else if ((inventoryItem != nullptr) &&
1824adc4f0dbSShawn McCarney                                  (inventoryItem->isPowerSupply))
1825028f7ebcSEddie James                         {
1826de629b6eSShawn McCarney                             fieldName = "PowerSupplies";
1827de629b6eSShawn McCarney                         }
1828adc4f0dbSShawn McCarney                         else
1829adc4f0dbSShawn McCarney                         {
1830adc4f0dbSShawn McCarney                             // Other power sensors are in SensorCollection
1831adc4f0dbSShawn McCarney                             continue;
1832adc4f0dbSShawn McCarney                         }
1833028f7ebcSEddie James                     }
1834de629b6eSShawn McCarney                     else
1835de629b6eSShawn McCarney                     {
1836de629b6eSShawn McCarney                         BMCWEB_LOG_ERROR << "Unsure how to handle sensorType "
1837de629b6eSShawn McCarney                                          << sensorType;
1838de629b6eSShawn McCarney                         continue;
1839de629b6eSShawn McCarney                     }
1840de629b6eSShawn McCarney 
1841de629b6eSShawn McCarney                     nlohmann::json& tempArray =
1842de629b6eSShawn McCarney                         SensorsAsyncResp->res.jsonValue[fieldName];
1843adc4f0dbSShawn McCarney                     if (fieldName == "PowerControl")
184449c53ac9SJohnathan Mantey                     {
1845adc4f0dbSShawn McCarney                         if (tempArray.empty())
18467ab06f49SGunnar Mills                         {
184795a3ecadSAnthony Wilson                             // Put multiple "sensors" into a single
184895a3ecadSAnthony Wilson                             // PowerControl. Follows MemberId naming and
184995a3ecadSAnthony Wilson                             // naming in power.hpp.
18507ab06f49SGunnar Mills                             tempArray.push_back(
1851adc4f0dbSShawn McCarney                                 {{"@odata.id",
1852adc4f0dbSShawn McCarney                                   "/redfish/v1/Chassis/" +
18537ab06f49SGunnar Mills                                       SensorsAsyncResp->chassisId + "/" +
1854adc4f0dbSShawn McCarney                                       SensorsAsyncResp->chassisSubNode + "#/" +
1855adc4f0dbSShawn McCarney                                       fieldName + "/0"}});
1856adc4f0dbSShawn McCarney                         }
1857adc4f0dbSShawn McCarney                         sensorJson = &(tempArray.back());
1858adc4f0dbSShawn McCarney                     }
1859adc4f0dbSShawn McCarney                     else if (fieldName == "PowerSupplies")
1860adc4f0dbSShawn McCarney                     {
1861adc4f0dbSShawn McCarney                         if (inventoryItem != nullptr)
1862adc4f0dbSShawn McCarney                         {
1863adc4f0dbSShawn McCarney                             sensorJson =
1864adc4f0dbSShawn McCarney                                 &(getPowerSupply(tempArray, *inventoryItem,
1865adc4f0dbSShawn McCarney                                                  SensorsAsyncResp->chassisId));
1866adc4f0dbSShawn McCarney                         }
186749c53ac9SJohnathan Mantey                     }
186849c53ac9SJohnathan Mantey                     else
186949c53ac9SJohnathan Mantey                     {
1870de629b6eSShawn McCarney                         tempArray.push_back(
187195a3ecadSAnthony Wilson                             {{"@odata.id",
187295a3ecadSAnthony Wilson                               "/redfish/v1/Chassis/" +
187349c53ac9SJohnathan Mantey                                   SensorsAsyncResp->chassisId + "/" +
187495a3ecadSAnthony Wilson                                   SensorsAsyncResp->chassisSubNode + "#/" +
187595a3ecadSAnthony Wilson                                   fieldName + "/"}});
1876adc4f0dbSShawn McCarney                         sensorJson = &(tempArray.back());
187749c53ac9SJohnathan Mantey                     }
187895a3ecadSAnthony Wilson                 }
1879de629b6eSShawn McCarney 
1880adc4f0dbSShawn McCarney                 if (sensorJson != nullptr)
1881adc4f0dbSShawn McCarney                 {
1882de629b6eSShawn McCarney                     objectInterfacesToJson(sensorName, sensorType,
188395a3ecadSAnthony Wilson                                            SensorsAsyncResp->chassisSubNode,
1884adc4f0dbSShawn McCarney                                            objDictEntry.second, *sensorJson,
1885adc4f0dbSShawn McCarney                                            inventoryItem);
1886adc4f0dbSShawn McCarney                 }
1887de629b6eSShawn McCarney             }
188849c53ac9SJohnathan Mantey             if (SensorsAsyncResp.use_count() == 1)
188949c53ac9SJohnathan Mantey             {
189049c53ac9SJohnathan Mantey                 sortJSONResponse(SensorsAsyncResp);
189149c53ac9SJohnathan Mantey                 if (SensorsAsyncResp->chassisSubNode == "Thermal")
18928bd25ccdSJames Feist                 {
18938bd25ccdSJames Feist                     populateFanRedundancy(SensorsAsyncResp);
18948bd25ccdSJames Feist                 }
189549c53ac9SJohnathan Mantey             }
1896de629b6eSShawn McCarney             BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
1897de629b6eSShawn McCarney         };
1898de629b6eSShawn McCarney 
1899de629b6eSShawn McCarney         // Find DBus object path that implements ObjectManager for the current
1900de629b6eSShawn McCarney         // connection.  If no mapping found, default to "/".
19018fb49dd6SShawn McCarney         auto iter = objectMgrPaths->find(connection);
1902de629b6eSShawn McCarney         const std::string& objectMgrPath =
19038fb49dd6SShawn McCarney             (iter != objectMgrPaths->end()) ? iter->second : "/";
1904de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
1905de629b6eSShawn McCarney                          << objectMgrPath;
1906de629b6eSShawn McCarney 
1907de629b6eSShawn McCarney         crow::connections::systemBus->async_method_call(
1908de629b6eSShawn McCarney             getManagedObjectsCb, connection, objectMgrPath,
1909de629b6eSShawn McCarney             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1910de629b6eSShawn McCarney     };
1911de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getSensorData exit";
1912de629b6eSShawn McCarney }
1913de629b6eSShawn McCarney 
191495a3ecadSAnthony Wilson void processSensorList(
191595a3ecadSAnthony Wilson     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
191695a3ecadSAnthony Wilson     std::shared_ptr<boost::container::flat_set<std::string>> sensorNames)
19171abe55efSEd Tanous {
191895a3ecadSAnthony Wilson     auto getConnectionCb =
191995a3ecadSAnthony Wilson         [SensorsAsyncResp, sensorNames](
192095a3ecadSAnthony Wilson             const boost::container::flat_set<std::string>& connections) {
192155c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "getConnectionCb enter";
1922de629b6eSShawn McCarney             auto getObjectManagerPathsCb =
192349c53ac9SJohnathan Mantey                 [SensorsAsyncResp, sensorNames, connections](
192495a3ecadSAnthony Wilson                     std::shared_ptr<
192595a3ecadSAnthony Wilson                         boost::container::flat_map<std::string, std::string>>
19268fb49dd6SShawn McCarney                         objectMgrPaths) {
1927de629b6eSShawn McCarney                     BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb enter";
1928adc4f0dbSShawn McCarney                     auto getInventoryItemsCb =
1929adc4f0dbSShawn McCarney                         [SensorsAsyncResp, sensorNames, connections,
1930adc4f0dbSShawn McCarney                          objectMgrPaths](
1931adc4f0dbSShawn McCarney                             std::shared_ptr<std::vector<InventoryItem>>
1932adc4f0dbSShawn McCarney                                 inventoryItems) {
1933adc4f0dbSShawn McCarney                             BMCWEB_LOG_DEBUG << "getInventoryItemsCb enter";
193449c53ac9SJohnathan Mantey                             // Get sensor data and store results in JSON
1935de629b6eSShawn McCarney                             getSensorData(SensorsAsyncResp, sensorNames,
1936adc4f0dbSShawn McCarney                                           connections, objectMgrPaths,
1937adc4f0dbSShawn McCarney                                           inventoryItems);
1938adc4f0dbSShawn McCarney                             BMCWEB_LOG_DEBUG << "getInventoryItemsCb exit";
1939adc4f0dbSShawn McCarney                         };
1940adc4f0dbSShawn McCarney 
1941adc4f0dbSShawn McCarney                     // Get inventory items associated with sensors
1942adc4f0dbSShawn McCarney                     getInventoryItems(SensorsAsyncResp, sensorNames,
1943adc4f0dbSShawn McCarney                                       objectMgrPaths,
1944adc4f0dbSShawn McCarney                                       std::move(getInventoryItemsCb));
1945adc4f0dbSShawn McCarney 
1946de629b6eSShawn McCarney                     BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb exit";
194708777fb0SLewanczyk, Dawid                 };
1948de629b6eSShawn McCarney 
194949c53ac9SJohnathan Mantey             // Get mapping from connection names to the DBus object
195049c53ac9SJohnathan Mantey             // paths that implement the ObjectManager interface
1951de629b6eSShawn McCarney             getObjectManagerPaths(SensorsAsyncResp,
1952de629b6eSShawn McCarney                                   std::move(getObjectManagerPathsCb));
195355c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "getConnectionCb exit";
195408777fb0SLewanczyk, Dawid         };
1955de629b6eSShawn McCarney 
1956de629b6eSShawn McCarney     // Get set of connections that provide sensor values
195795a3ecadSAnthony Wilson     getConnections(SensorsAsyncResp, sensorNames, std::move(getConnectionCb));
195895a3ecadSAnthony Wilson }
195995a3ecadSAnthony Wilson 
196095a3ecadSAnthony Wilson /**
196195a3ecadSAnthony Wilson  * @brief Entry point for retrieving sensors data related to requested
196295a3ecadSAnthony Wilson  *        chassis.
196395a3ecadSAnthony Wilson  * @param SensorsAsyncResp   Pointer to object holding response data
196495a3ecadSAnthony Wilson  */
196595a3ecadSAnthony Wilson void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
196695a3ecadSAnthony Wilson {
196795a3ecadSAnthony Wilson     BMCWEB_LOG_DEBUG << "getChassisData enter";
196895a3ecadSAnthony Wilson     auto getChassisCb =
196995a3ecadSAnthony Wilson         [SensorsAsyncResp](
197095a3ecadSAnthony Wilson             std::shared_ptr<boost::container::flat_set<std::string>>
197195a3ecadSAnthony Wilson                 sensorNames) {
197295a3ecadSAnthony Wilson             BMCWEB_LOG_DEBUG << "getChassisCb enter";
197395a3ecadSAnthony Wilson             processSensorList(SensorsAsyncResp, sensorNames);
197455c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "getChassisCb exit";
197508777fb0SLewanczyk, Dawid         };
19764f9a2130SJennifer Lee     SensorsAsyncResp->res.jsonValue["Redundancy"] = nlohmann::json::array();
197708777fb0SLewanczyk, Dawid 
197826f03899SShawn McCarney     // Get set of sensors in chassis
1979588c3f0dSKowalski, Kamil     getChassis(SensorsAsyncResp, std::move(getChassisCb));
198055c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisData exit";
1981*271584abSEd Tanous }
198208777fb0SLewanczyk, Dawid 
1983413961deSRichard Marian Thomaiyar /**
198449c53ac9SJohnathan Mantey  * @brief Find the requested sensorName in the list of all sensors supplied by
198549c53ac9SJohnathan Mantey  * the chassis node
198649c53ac9SJohnathan Mantey  *
198749c53ac9SJohnathan Mantey  * @param sensorName   The sensor name supplied in the PATCH request
198849c53ac9SJohnathan Mantey  * @param sensorsList  The list of sensors managed by the chassis node
198949c53ac9SJohnathan Mantey  * @param sensorsModified  The list of sensors that were found as a result of
199049c53ac9SJohnathan Mantey  *                         repeated calls to this function
199149c53ac9SJohnathan Mantey  */
199249c53ac9SJohnathan Mantey bool findSensorNameUsingSensorPath(
19930a86febdSRichard Marian Thomaiyar     std::string_view sensorName,
199449c53ac9SJohnathan Mantey     boost::container::flat_set<std::string>& sensorsList,
199549c53ac9SJohnathan Mantey     boost::container::flat_set<std::string>& sensorsModified)
199649c53ac9SJohnathan Mantey {
19970a86febdSRichard Marian Thomaiyar     for (std::string_view chassisSensor : sensorsList)
199849c53ac9SJohnathan Mantey     {
19990a86febdSRichard Marian Thomaiyar         std::size_t pos = chassisSensor.rfind("/");
20000a86febdSRichard Marian Thomaiyar         if (pos >= (chassisSensor.size() - 1))
200149c53ac9SJohnathan Mantey         {
200249c53ac9SJohnathan Mantey             continue;
200349c53ac9SJohnathan Mantey         }
20040a86febdSRichard Marian Thomaiyar         std::string_view thisSensorName = chassisSensor.substr(pos + 1);
200549c53ac9SJohnathan Mantey         if (thisSensorName == sensorName)
200649c53ac9SJohnathan Mantey         {
200749c53ac9SJohnathan Mantey             sensorsModified.emplace(chassisSensor);
200849c53ac9SJohnathan Mantey             return true;
200949c53ac9SJohnathan Mantey         }
201049c53ac9SJohnathan Mantey     }
201149c53ac9SJohnathan Mantey     return false;
201249c53ac9SJohnathan Mantey }
201349c53ac9SJohnathan Mantey 
201449c53ac9SJohnathan Mantey /**
2015413961deSRichard Marian Thomaiyar  * @brief Entry point for overriding sensor values of given sensor
2016413961deSRichard Marian Thomaiyar  *
2017413961deSRichard Marian Thomaiyar  * @param res   response object
2018413961deSRichard Marian Thomaiyar  * @param req   request object
2019413961deSRichard Marian Thomaiyar  * @param params   parameter passed for CRUD
2020413961deSRichard Marian Thomaiyar  * @param typeList   TypeList of sensors for the resource queried
2021413961deSRichard Marian Thomaiyar  * @param chassisSubNode   Chassis Node for which the query has to happen
2022413961deSRichard Marian Thomaiyar  */
2023413961deSRichard Marian Thomaiyar void setSensorOverride(crow::Response& res, const crow::Request& req,
2024413961deSRichard Marian Thomaiyar                        const std::vector<std::string>& params,
202585e1424fSEd Tanous                        const std::vector<const char*> typeList,
2026413961deSRichard Marian Thomaiyar                        const std::string& chassisSubNode)
2027413961deSRichard Marian Thomaiyar {
2028413961deSRichard Marian Thomaiyar 
2029413961deSRichard Marian Thomaiyar     // TODO: Need to figure out dynamic way to restrict patch (Set Sensor
2030413961deSRichard Marian Thomaiyar     // override) based on another d-bus announcement to be more generic.
2031413961deSRichard Marian Thomaiyar     if (params.size() != 1)
2032413961deSRichard Marian Thomaiyar     {
2033413961deSRichard Marian Thomaiyar         messages::internalError(res);
2034413961deSRichard Marian Thomaiyar         res.end();
2035413961deSRichard Marian Thomaiyar         return;
2036413961deSRichard Marian Thomaiyar     }
2037f65af9e8SRichard Marian Thomaiyar 
2038f65af9e8SRichard Marian Thomaiyar     std::unordered_map<std::string, std::vector<nlohmann::json>> allCollections;
2039f65af9e8SRichard Marian Thomaiyar     std::optional<std::vector<nlohmann::json>> temperatureCollections;
2040f65af9e8SRichard Marian Thomaiyar     std::optional<std::vector<nlohmann::json>> fanCollections;
2041f65af9e8SRichard Marian Thomaiyar     std::vector<nlohmann::json> voltageCollections;
2042f65af9e8SRichard Marian Thomaiyar     BMCWEB_LOG_INFO << "setSensorOverride for subNode" << chassisSubNode
2043f65af9e8SRichard Marian Thomaiyar                     << "\n";
2044f65af9e8SRichard Marian Thomaiyar 
2045413961deSRichard Marian Thomaiyar     if (chassisSubNode == "Thermal")
2046413961deSRichard Marian Thomaiyar     {
2047f65af9e8SRichard Marian Thomaiyar         if (!json_util::readJson(req, res, "Temperatures",
2048f65af9e8SRichard Marian Thomaiyar                                  temperatureCollections, "Fans",
2049f65af9e8SRichard Marian Thomaiyar                                  fanCollections))
2050f65af9e8SRichard Marian Thomaiyar         {
2051f65af9e8SRichard Marian Thomaiyar             return;
2052f65af9e8SRichard Marian Thomaiyar         }
2053f65af9e8SRichard Marian Thomaiyar         if (!temperatureCollections && !fanCollections)
2054f65af9e8SRichard Marian Thomaiyar         {
2055f65af9e8SRichard Marian Thomaiyar             messages::resourceNotFound(res, "Thermal",
2056f65af9e8SRichard Marian Thomaiyar                                        "Temperatures / Voltages");
2057f65af9e8SRichard Marian Thomaiyar             res.end();
2058f65af9e8SRichard Marian Thomaiyar             return;
2059f65af9e8SRichard Marian Thomaiyar         }
2060f65af9e8SRichard Marian Thomaiyar         if (temperatureCollections)
2061f65af9e8SRichard Marian Thomaiyar         {
2062f65af9e8SRichard Marian Thomaiyar             allCollections.emplace("Temperatures",
2063f65af9e8SRichard Marian Thomaiyar                                    *std::move(temperatureCollections));
2064f65af9e8SRichard Marian Thomaiyar         }
2065f65af9e8SRichard Marian Thomaiyar         if (fanCollections)
2066f65af9e8SRichard Marian Thomaiyar         {
2067f65af9e8SRichard Marian Thomaiyar             allCollections.emplace("Fans", *std::move(fanCollections));
2068f65af9e8SRichard Marian Thomaiyar         }
2069413961deSRichard Marian Thomaiyar     }
2070413961deSRichard Marian Thomaiyar     else if (chassisSubNode == "Power")
2071413961deSRichard Marian Thomaiyar     {
2072f65af9e8SRichard Marian Thomaiyar         if (!json_util::readJson(req, res, "Voltages", voltageCollections))
2073f65af9e8SRichard Marian Thomaiyar         {
2074f65af9e8SRichard Marian Thomaiyar             return;
2075f65af9e8SRichard Marian Thomaiyar         }
2076f65af9e8SRichard Marian Thomaiyar         allCollections.emplace("Voltages", std::move(voltageCollections));
2077413961deSRichard Marian Thomaiyar     }
2078413961deSRichard Marian Thomaiyar     else
2079413961deSRichard Marian Thomaiyar     {
2080413961deSRichard Marian Thomaiyar         res.result(boost::beast::http::status::not_found);
2081413961deSRichard Marian Thomaiyar         res.end();
2082413961deSRichard Marian Thomaiyar         return;
2083413961deSRichard Marian Thomaiyar     }
2084413961deSRichard Marian Thomaiyar 
2085f65af9e8SRichard Marian Thomaiyar     const char* propertyValueName;
2086f65af9e8SRichard Marian Thomaiyar     std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
2087413961deSRichard Marian Thomaiyar     std::string memberId;
2088413961deSRichard Marian Thomaiyar     double value;
2089f65af9e8SRichard Marian Thomaiyar     for (auto& collectionItems : allCollections)
2090f65af9e8SRichard Marian Thomaiyar     {
2091f65af9e8SRichard Marian Thomaiyar         if (collectionItems.first == "Temperatures")
2092f65af9e8SRichard Marian Thomaiyar         {
2093f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingCelsius";
2094f65af9e8SRichard Marian Thomaiyar         }
2095f65af9e8SRichard Marian Thomaiyar         else if (collectionItems.first == "Fans")
2096f65af9e8SRichard Marian Thomaiyar         {
2097f65af9e8SRichard Marian Thomaiyar             propertyValueName = "Reading";
2098f65af9e8SRichard Marian Thomaiyar         }
2099f65af9e8SRichard Marian Thomaiyar         else
2100f65af9e8SRichard Marian Thomaiyar         {
2101f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingVolts";
2102f65af9e8SRichard Marian Thomaiyar         }
2103f65af9e8SRichard Marian Thomaiyar         for (auto& item : collectionItems.second)
2104f65af9e8SRichard Marian Thomaiyar         {
2105f65af9e8SRichard Marian Thomaiyar             if (!json_util::readJson(item, res, "MemberId", memberId,
2106413961deSRichard Marian Thomaiyar                                      propertyValueName, value))
2107413961deSRichard Marian Thomaiyar             {
2108413961deSRichard Marian Thomaiyar                 return;
2109413961deSRichard Marian Thomaiyar             }
2110f65af9e8SRichard Marian Thomaiyar             overrideMap.emplace(memberId,
2111f65af9e8SRichard Marian Thomaiyar                                 std::make_pair(value, collectionItems.first));
2112f65af9e8SRichard Marian Thomaiyar         }
2113f65af9e8SRichard Marian Thomaiyar     }
2114413961deSRichard Marian Thomaiyar     const std::string& chassisName = params[0];
2115413961deSRichard Marian Thomaiyar     auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
2116413961deSRichard Marian Thomaiyar         res, chassisName, typeList, chassisSubNode);
211749c53ac9SJohnathan Mantey     auto getChassisSensorListCb = [sensorAsyncResp,
211849c53ac9SJohnathan Mantey                                    overrideMap](const std::shared_ptr<
211949c53ac9SJohnathan Mantey                                                 boost::container::flat_set<
212049c53ac9SJohnathan Mantey                                                     std::string>>
212149c53ac9SJohnathan Mantey                                                     sensorsList) {
212249c53ac9SJohnathan Mantey         // Match sensor names in the PATCH request to those managed by the
212349c53ac9SJohnathan Mantey         // chassis node
212449c53ac9SJohnathan Mantey         const std::shared_ptr<boost::container::flat_set<std::string>>
212549c53ac9SJohnathan Mantey             sensorNames =
212649c53ac9SJohnathan Mantey                 std::make_shared<boost::container::flat_set<std::string>>();
2127f65af9e8SRichard Marian Thomaiyar         for (const auto& item : overrideMap)
2128413961deSRichard Marian Thomaiyar         {
2129f65af9e8SRichard Marian Thomaiyar             const auto& sensor = item.first;
213049c53ac9SJohnathan Mantey             if (!findSensorNameUsingSensorPath(sensor, *sensorsList,
213149c53ac9SJohnathan Mantey                                                *sensorNames))
2132f65af9e8SRichard Marian Thomaiyar             {
2133f65af9e8SRichard Marian Thomaiyar                 BMCWEB_LOG_INFO << "Unable to find memberId " << item.first;
2134413961deSRichard Marian Thomaiyar                 messages::resourceNotFound(sensorAsyncResp->res,
2135f65af9e8SRichard Marian Thomaiyar                                            item.second.second, item.first);
2136413961deSRichard Marian Thomaiyar                 return;
2137413961deSRichard Marian Thomaiyar             }
2138f65af9e8SRichard Marian Thomaiyar         }
2139413961deSRichard Marian Thomaiyar         // Get the connection to which the memberId belongs
2140413961deSRichard Marian Thomaiyar         auto getObjectsWithConnectionCb =
2141f65af9e8SRichard Marian Thomaiyar             [sensorAsyncResp, overrideMap](
2142413961deSRichard Marian Thomaiyar                 const boost::container::flat_set<std::string>& connections,
2143413961deSRichard Marian Thomaiyar                 const std::set<std::pair<std::string, std::string>>&
2144413961deSRichard Marian Thomaiyar                     objectsWithConnection) {
2145f65af9e8SRichard Marian Thomaiyar                 if (objectsWithConnection.size() != overrideMap.size())
2146413961deSRichard Marian Thomaiyar                 {
2147413961deSRichard Marian Thomaiyar                     BMCWEB_LOG_INFO
2148f65af9e8SRichard Marian Thomaiyar                         << "Unable to find all objects with proper connection "
2149f65af9e8SRichard Marian Thomaiyar                         << objectsWithConnection.size() << " requested "
2150f65af9e8SRichard Marian Thomaiyar                         << overrideMap.size() << "\n";
2151413961deSRichard Marian Thomaiyar                     messages::resourceNotFound(
2152413961deSRichard Marian Thomaiyar                         sensorAsyncResp->res,
2153413961deSRichard Marian Thomaiyar                         sensorAsyncResp->chassisSubNode == "Thermal"
2154413961deSRichard Marian Thomaiyar                             ? "Temperatures"
2155413961deSRichard Marian Thomaiyar                             : "Voltages",
2156f65af9e8SRichard Marian Thomaiyar                         "Count");
2157f65af9e8SRichard Marian Thomaiyar                     return;
2158f65af9e8SRichard Marian Thomaiyar                 }
2159f65af9e8SRichard Marian Thomaiyar                 for (const auto& item : objectsWithConnection)
2160f65af9e8SRichard Marian Thomaiyar                 {
2161f65af9e8SRichard Marian Thomaiyar 
2162f65af9e8SRichard Marian Thomaiyar                     auto lastPos = item.first.rfind('/');
2163f65af9e8SRichard Marian Thomaiyar                     if (lastPos == std::string::npos)
2164f65af9e8SRichard Marian Thomaiyar                     {
2165f65af9e8SRichard Marian Thomaiyar                         messages::internalError(sensorAsyncResp->res);
2166f65af9e8SRichard Marian Thomaiyar                         return;
2167f65af9e8SRichard Marian Thomaiyar                     }
2168f65af9e8SRichard Marian Thomaiyar                     std::string sensorName = item.first.substr(lastPos + 1);
2169f65af9e8SRichard Marian Thomaiyar 
2170f65af9e8SRichard Marian Thomaiyar                     const auto& iterator = overrideMap.find(sensorName);
2171f65af9e8SRichard Marian Thomaiyar                     if (iterator == overrideMap.end())
2172f65af9e8SRichard Marian Thomaiyar                     {
2173f65af9e8SRichard Marian Thomaiyar                         BMCWEB_LOG_INFO << "Unable to find sensor object"
2174f65af9e8SRichard Marian Thomaiyar                                         << item.first << "\n";
2175f65af9e8SRichard Marian Thomaiyar                         messages::internalError(sensorAsyncResp->res);
2176413961deSRichard Marian Thomaiyar                         return;
2177413961deSRichard Marian Thomaiyar                     }
2178413961deSRichard Marian Thomaiyar                     crow::connections::systemBus->async_method_call(
2179f65af9e8SRichard Marian Thomaiyar                         [sensorAsyncResp](const boost::system::error_code ec) {
2180413961deSRichard Marian Thomaiyar                             if (ec)
2181413961deSRichard Marian Thomaiyar                             {
2182413961deSRichard Marian Thomaiyar                                 BMCWEB_LOG_DEBUG
2183f65af9e8SRichard Marian Thomaiyar                                     << "setOverrideValueStatus DBUS error: "
2184413961deSRichard Marian Thomaiyar                                     << ec;
2185413961deSRichard Marian Thomaiyar                                 messages::internalError(sensorAsyncResp->res);
2186413961deSRichard Marian Thomaiyar                                 return;
2187413961deSRichard Marian Thomaiyar                             }
2188413961deSRichard Marian Thomaiyar                         },
2189f65af9e8SRichard Marian Thomaiyar                         item.second, item.first,
2190413961deSRichard Marian Thomaiyar                         "org.freedesktop.DBus.Properties", "Set",
2191413961deSRichard Marian Thomaiyar                         "xyz.openbmc_project.Sensor.Value", "Value",
2192f65af9e8SRichard Marian Thomaiyar                         sdbusplus::message::variant<double>(
2193f65af9e8SRichard Marian Thomaiyar                             iterator->second.first));
2194f65af9e8SRichard Marian Thomaiyar                 }
2195413961deSRichard Marian Thomaiyar             };
2196413961deSRichard Marian Thomaiyar         // Get object with connection for the given sensor name
2197413961deSRichard Marian Thomaiyar         getObjectsWithConnection(sensorAsyncResp, sensorNames,
2198413961deSRichard Marian Thomaiyar                                  std::move(getObjectsWithConnectionCb));
2199413961deSRichard Marian Thomaiyar     };
2200413961deSRichard Marian Thomaiyar     // get full sensor list for the given chassisId and cross verify the sensor.
2201413961deSRichard Marian Thomaiyar     getChassis(sensorAsyncResp, std::move(getChassisSensorListCb));
2202413961deSRichard Marian Thomaiyar }
2203413961deSRichard Marian Thomaiyar 
220495a3ecadSAnthony Wilson class SensorCollection : public Node
220595a3ecadSAnthony Wilson {
220695a3ecadSAnthony Wilson   public:
220795a3ecadSAnthony Wilson     SensorCollection(CrowApp& app) :
220895a3ecadSAnthony Wilson         Node(app, "/redfish/v1/Chassis/<str>/Sensors", std::string())
220995a3ecadSAnthony Wilson     {
221095a3ecadSAnthony Wilson         entityPrivileges = {
221195a3ecadSAnthony Wilson             {boost::beast::http::verb::get, {{"Login"}}},
221295a3ecadSAnthony Wilson             {boost::beast::http::verb::head, {{"Login"}}},
221395a3ecadSAnthony Wilson             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
221495a3ecadSAnthony Wilson             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
221595a3ecadSAnthony Wilson             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
221695a3ecadSAnthony Wilson             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
221795a3ecadSAnthony Wilson     }
221895a3ecadSAnthony Wilson 
221995a3ecadSAnthony Wilson   private:
222095a3ecadSAnthony Wilson     std::vector<const char*> typeList = {
222195a3ecadSAnthony Wilson         "/xyz/openbmc_project/sensors/power",
222295a3ecadSAnthony Wilson         "/xyz/openbmc_project/sensors/current"};
222395a3ecadSAnthony Wilson     void doGet(crow::Response& res, const crow::Request& req,
222495a3ecadSAnthony Wilson                const std::vector<std::string>& params) override
222595a3ecadSAnthony Wilson     {
222695a3ecadSAnthony Wilson         BMCWEB_LOG_DEBUG << "SensorCollection doGet enter";
222795a3ecadSAnthony Wilson         if (params.size() != 1)
222895a3ecadSAnthony Wilson         {
222995a3ecadSAnthony Wilson             BMCWEB_LOG_DEBUG << "SensorCollection doGet param size < 1";
223095a3ecadSAnthony Wilson             messages::internalError(res);
223195a3ecadSAnthony Wilson             res.end();
223295a3ecadSAnthony Wilson             return;
223395a3ecadSAnthony Wilson         }
223495a3ecadSAnthony Wilson 
223595a3ecadSAnthony Wilson         const std::string& chassisId = params[0];
223695a3ecadSAnthony Wilson         std::shared_ptr<SensorsAsyncResp> asyncResp =
223795a3ecadSAnthony Wilson             std::make_shared<SensorsAsyncResp>(res, chassisId, typeList,
223895a3ecadSAnthony Wilson                                                "Sensors");
223995a3ecadSAnthony Wilson 
224095a3ecadSAnthony Wilson         auto getChassisCb =
224195a3ecadSAnthony Wilson             [asyncResp](std::shared_ptr<boost::container::flat_set<std::string>>
224295a3ecadSAnthony Wilson                             sensorNames) {
224395a3ecadSAnthony Wilson                 BMCWEB_LOG_DEBUG << "getChassisCb enter";
224495a3ecadSAnthony Wilson 
224595a3ecadSAnthony Wilson                 nlohmann::json& entriesArray =
224695a3ecadSAnthony Wilson                     asyncResp->res.jsonValue["Members"];
224795a3ecadSAnthony Wilson                 for (auto& sensor : *sensorNames)
224895a3ecadSAnthony Wilson                 {
224995a3ecadSAnthony Wilson                     BMCWEB_LOG_DEBUG << "Adding sensor: " << sensor;
225095a3ecadSAnthony Wilson 
225195a3ecadSAnthony Wilson                     std::size_t lastPos = sensor.rfind("/");
225295a3ecadSAnthony Wilson                     if (lastPos == std::string::npos ||
225395a3ecadSAnthony Wilson                         lastPos + 1 >= sensor.size())
225495a3ecadSAnthony Wilson                     {
225595a3ecadSAnthony Wilson                         BMCWEB_LOG_ERROR << "Invalid sensor path: " << sensor;
225695a3ecadSAnthony Wilson                         messages::internalError(asyncResp->res);
225795a3ecadSAnthony Wilson                         return;
225895a3ecadSAnthony Wilson                     }
225995a3ecadSAnthony Wilson                     std::string sensorName = sensor.substr(lastPos + 1);
226095a3ecadSAnthony Wilson                     entriesArray.push_back(
226195a3ecadSAnthony Wilson                         {{"@odata.id",
226295a3ecadSAnthony Wilson                           "/redfish/v1/Chassis/" + asyncResp->chassisId + "/" +
226395a3ecadSAnthony Wilson                               asyncResp->chassisSubNode + "/" + sensorName}});
226495a3ecadSAnthony Wilson                 }
226595a3ecadSAnthony Wilson 
226695a3ecadSAnthony Wilson                 asyncResp->res.jsonValue["Members@odata.count"] =
226795a3ecadSAnthony Wilson                     entriesArray.size();
226895a3ecadSAnthony Wilson                 BMCWEB_LOG_DEBUG << "getChassisCb exit";
226995a3ecadSAnthony Wilson             };
227095a3ecadSAnthony Wilson 
227195a3ecadSAnthony Wilson         // Get set of sensors in chassis
227295a3ecadSAnthony Wilson         getChassis(asyncResp, std::move(getChassisCb));
227395a3ecadSAnthony Wilson         BMCWEB_LOG_DEBUG << "SensorCollection doGet exit";
227495a3ecadSAnthony Wilson     }
227595a3ecadSAnthony Wilson };
227695a3ecadSAnthony Wilson 
227795a3ecadSAnthony Wilson class Sensor : public Node
227895a3ecadSAnthony Wilson {
227995a3ecadSAnthony Wilson   public:
228095a3ecadSAnthony Wilson     Sensor(CrowApp& app) :
228195a3ecadSAnthony Wilson         Node(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/", std::string(),
228295a3ecadSAnthony Wilson              std::string())
228395a3ecadSAnthony Wilson     {
228495a3ecadSAnthony Wilson         entityPrivileges = {
228595a3ecadSAnthony Wilson             {boost::beast::http::verb::get, {{"Login"}}},
228695a3ecadSAnthony Wilson             {boost::beast::http::verb::head, {{"Login"}}},
228795a3ecadSAnthony Wilson             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
228895a3ecadSAnthony Wilson             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
228995a3ecadSAnthony Wilson             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
229095a3ecadSAnthony Wilson             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
229195a3ecadSAnthony Wilson     }
229295a3ecadSAnthony Wilson 
229395a3ecadSAnthony Wilson   private:
229495a3ecadSAnthony Wilson     void doGet(crow::Response& res, const crow::Request& req,
229595a3ecadSAnthony Wilson                const std::vector<std::string>& params) override
229695a3ecadSAnthony Wilson     {
229795a3ecadSAnthony Wilson         BMCWEB_LOG_DEBUG << "Sensor doGet enter";
229895a3ecadSAnthony Wilson         if (params.size() != 2)
229995a3ecadSAnthony Wilson         {
230095a3ecadSAnthony Wilson             BMCWEB_LOG_DEBUG << "Sensor doGet param size < 2";
230195a3ecadSAnthony Wilson             messages::internalError(res);
230295a3ecadSAnthony Wilson             res.end();
230395a3ecadSAnthony Wilson             return;
230495a3ecadSAnthony Wilson         }
230595a3ecadSAnthony Wilson         const std::string& chassisId = params[0];
230695a3ecadSAnthony Wilson         std::shared_ptr<SensorsAsyncResp> asyncResp =
230795a3ecadSAnthony Wilson             std::make_shared<SensorsAsyncResp>(
230895a3ecadSAnthony Wilson                 res, chassisId, std::vector<const char*>(), "Sensors");
230995a3ecadSAnthony Wilson 
231095a3ecadSAnthony Wilson         const std::string& sensorName = params[1];
231195a3ecadSAnthony Wilson         const std::array<const char*, 1> interfaces = {
231295a3ecadSAnthony Wilson             "xyz.openbmc_project.Sensor.Value"};
231395a3ecadSAnthony Wilson 
231495a3ecadSAnthony Wilson         // Get a list of all of the sensors that implement Sensor.Value
231595a3ecadSAnthony Wilson         // and get the path and service name associated with the sensor
231695a3ecadSAnthony Wilson         crow::connections::systemBus->async_method_call(
231795a3ecadSAnthony Wilson             [asyncResp, sensorName](const boost::system::error_code ec,
231895a3ecadSAnthony Wilson                                     const GetSubTreeType& subtree) {
231995a3ecadSAnthony Wilson                 BMCWEB_LOG_DEBUG << "respHandler1 enter";
232095a3ecadSAnthony Wilson                 if (ec)
232195a3ecadSAnthony Wilson                 {
232295a3ecadSAnthony Wilson                     messages::internalError(asyncResp->res);
232395a3ecadSAnthony Wilson                     BMCWEB_LOG_ERROR << "Sensor getSensorPaths resp_handler: "
232495a3ecadSAnthony Wilson                                      << "Dbus error " << ec;
232595a3ecadSAnthony Wilson                     return;
232695a3ecadSAnthony Wilson                 }
232795a3ecadSAnthony Wilson 
232895a3ecadSAnthony Wilson                 GetSubTreeType::const_iterator it = std::find_if(
232995a3ecadSAnthony Wilson                     subtree.begin(), subtree.end(),
233095a3ecadSAnthony Wilson                     [sensorName](
233195a3ecadSAnthony Wilson                         const std::pair<
233295a3ecadSAnthony Wilson                             std::string,
233395a3ecadSAnthony Wilson                             std::vector<std::pair<std::string,
233495a3ecadSAnthony Wilson                                                   std::vector<std::string>>>>&
233595a3ecadSAnthony Wilson                             object) {
233695a3ecadSAnthony Wilson                         std::string_view sensor = object.first;
233795a3ecadSAnthony Wilson                         std::size_t lastPos = sensor.rfind("/");
233895a3ecadSAnthony Wilson                         if (lastPos == std::string::npos ||
233995a3ecadSAnthony Wilson                             lastPos + 1 >= sensor.size())
234095a3ecadSAnthony Wilson                         {
234195a3ecadSAnthony Wilson                             BMCWEB_LOG_ERROR << "Invalid sensor path: "
234295a3ecadSAnthony Wilson                                              << sensor;
234395a3ecadSAnthony Wilson                             return false;
234495a3ecadSAnthony Wilson                         }
234595a3ecadSAnthony Wilson                         std::string_view name = sensor.substr(lastPos + 1);
234695a3ecadSAnthony Wilson 
234795a3ecadSAnthony Wilson                         return name == sensorName;
234895a3ecadSAnthony Wilson                     });
234995a3ecadSAnthony Wilson 
235095a3ecadSAnthony Wilson                 if (it == subtree.end())
235195a3ecadSAnthony Wilson                 {
235295a3ecadSAnthony Wilson                     BMCWEB_LOG_ERROR << "Could not find path for sensor: "
235395a3ecadSAnthony Wilson                                      << sensorName;
235495a3ecadSAnthony Wilson                     messages::resourceNotFound(asyncResp->res, "Sensor",
235595a3ecadSAnthony Wilson                                                sensorName);
235695a3ecadSAnthony Wilson                     return;
235795a3ecadSAnthony Wilson                 }
235895a3ecadSAnthony Wilson                 std::string_view sensorPath = (*it).first;
235995a3ecadSAnthony Wilson                 BMCWEB_LOG_DEBUG << "Found sensor path for sensor '"
236095a3ecadSAnthony Wilson                                  << sensorName << "': " << sensorPath;
236195a3ecadSAnthony Wilson 
236295a3ecadSAnthony Wilson                 const std::shared_ptr<boost::container::flat_set<std::string>>
236395a3ecadSAnthony Wilson                     sensorList = std::make_shared<
236495a3ecadSAnthony Wilson                         boost::container::flat_set<std::string>>();
236595a3ecadSAnthony Wilson 
236695a3ecadSAnthony Wilson                 sensorList->emplace(sensorPath);
236795a3ecadSAnthony Wilson                 processSensorList(asyncResp, sensorList);
236895a3ecadSAnthony Wilson                 BMCWEB_LOG_DEBUG << "respHandler1 exit";
236995a3ecadSAnthony Wilson             },
237095a3ecadSAnthony Wilson             "xyz.openbmc_project.ObjectMapper",
237195a3ecadSAnthony Wilson             "/xyz/openbmc_project/object_mapper",
237295a3ecadSAnthony Wilson             "xyz.openbmc_project.ObjectMapper", "GetSubTree",
237395a3ecadSAnthony Wilson             "/xyz/openbmc_project/sensors", 2, interfaces);
237495a3ecadSAnthony Wilson     }
237595a3ecadSAnthony Wilson };
237695a3ecadSAnthony Wilson 
237708777fb0SLewanczyk, Dawid } // namespace redfish
2378