xref: /openbmc/bmcweb/features/redfish/lib/sensors.hpp (revision 9e27a22edc4434ec577c2eb4034edc6874088413)
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 <boost/algorithm/string/predicate.hpp>
2108777fb0SLewanczyk, Dawid #include <boost/algorithm/string/split.hpp>
2208777fb0SLewanczyk, Dawid #include <boost/container/flat_map.hpp>
2308777fb0SLewanczyk, Dawid #include <boost/range/algorithm/replace_copy_if.hpp>
24*9e27a22eSEd Tanous #include <cmath>
251abe55efSEd Tanous #include <dbus_singleton.hpp>
26413961deSRichard Marian Thomaiyar #include <utils/json_utils.hpp>
27abf2add6SEd Tanous #include <variant>
2808777fb0SLewanczyk, Dawid 
291abe55efSEd Tanous namespace redfish
301abe55efSEd Tanous {
3108777fb0SLewanczyk, Dawid 
3208777fb0SLewanczyk, Dawid using GetSubTreeType = std::vector<
3308777fb0SLewanczyk, Dawid     std::pair<std::string,
3408777fb0SLewanczyk, Dawid               std::vector<std::pair<std::string, std::vector<std::string>>>>>;
3508777fb0SLewanczyk, Dawid 
36adc4f0dbSShawn McCarney using SensorVariant =
37adc4f0dbSShawn McCarney     std::variant<int64_t, double, uint32_t, bool, std::string>;
38aa2e59c1SEd Tanous 
3908777fb0SLewanczyk, Dawid using ManagedObjectsVectorType = std::vector<std::pair<
40aa2e59c1SEd Tanous     sdbusplus::message::object_path,
4108777fb0SLewanczyk, Dawid     boost::container::flat_map<
42aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>>>;
4308777fb0SLewanczyk, Dawid 
4408777fb0SLewanczyk, Dawid /**
45588c3f0dSKowalski, Kamil  * SensorsAsyncResp
4608777fb0SLewanczyk, Dawid  * Gathers data needed for response processing after async calls are done
4708777fb0SLewanczyk, Dawid  */
481abe55efSEd Tanous class SensorsAsyncResp
491abe55efSEd Tanous {
5008777fb0SLewanczyk, Dawid   public:
51271584abSEd Tanous     SensorsAsyncResp(crow::Response& response, const std::string& chassisIdIn,
52271584abSEd Tanous                      const std::vector<const char*> typesIn,
532474adfaSEd Tanous                      const std::string& subNode) :
5443b761d0SEd Tanous         res(response),
55271584abSEd Tanous         chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode)
561abe55efSEd Tanous     {
5708777fb0SLewanczyk, Dawid     }
5808777fb0SLewanczyk, Dawid 
591abe55efSEd Tanous     ~SensorsAsyncResp()
601abe55efSEd Tanous     {
611abe55efSEd Tanous         if (res.result() == boost::beast::http::status::internal_server_error)
621abe55efSEd Tanous         {
631abe55efSEd Tanous             // Reset the json object to clear out any data that made it in
641abe55efSEd Tanous             // before the error happened todo(ed) handle error condition with
651abe55efSEd Tanous             // proper code
6655c7b7a2SEd Tanous             res.jsonValue = nlohmann::json::object();
6708777fb0SLewanczyk, Dawid         }
6808777fb0SLewanczyk, Dawid         res.end();
6908777fb0SLewanczyk, Dawid     }
70588c3f0dSKowalski, Kamil 
7155c7b7a2SEd Tanous     crow::Response& res;
72588c3f0dSKowalski, Kamil     std::string chassisId{};
7308777fb0SLewanczyk, Dawid     const std::vector<const char*> types;
742474adfaSEd Tanous     std::string chassisSubNode{};
7508777fb0SLewanczyk, Dawid };
7608777fb0SLewanczyk, Dawid 
7708777fb0SLewanczyk, Dawid /**
78adc4f0dbSShawn McCarney  * D-Bus inventory item associated with one or more sensors.
79adc4f0dbSShawn McCarney  */
80adc4f0dbSShawn McCarney class InventoryItem
81adc4f0dbSShawn McCarney {
82adc4f0dbSShawn McCarney   public:
83adc4f0dbSShawn McCarney     InventoryItem(const std::string& objPath) :
84adc4f0dbSShawn McCarney         objectPath(objPath), name(), isPresent(true), isFunctional(true),
85adc4f0dbSShawn McCarney         isPowerSupply(false), manufacturer(), model(), partNumber(),
86adc4f0dbSShawn McCarney         serialNumber(), sensors()
87adc4f0dbSShawn McCarney     {
88adc4f0dbSShawn McCarney         // Set inventory item name to last node of object path
89adc4f0dbSShawn McCarney         auto pos = objectPath.rfind('/');
90adc4f0dbSShawn McCarney         if ((pos != std::string::npos) && ((pos + 1) < objectPath.size()))
91adc4f0dbSShawn McCarney         {
92adc4f0dbSShawn McCarney             name = objectPath.substr(pos + 1);
93adc4f0dbSShawn McCarney         }
94adc4f0dbSShawn McCarney     }
95adc4f0dbSShawn McCarney 
96adc4f0dbSShawn McCarney     std::string objectPath;
97adc4f0dbSShawn McCarney     std::string name;
98adc4f0dbSShawn McCarney     bool isPresent;
99adc4f0dbSShawn McCarney     bool isFunctional;
100adc4f0dbSShawn McCarney     bool isPowerSupply;
101adc4f0dbSShawn McCarney     std::string manufacturer;
102adc4f0dbSShawn McCarney     std::string model;
103adc4f0dbSShawn McCarney     std::string partNumber;
104adc4f0dbSShawn McCarney     std::string serialNumber;
105adc4f0dbSShawn McCarney     std::set<std::string> sensors;
106adc4f0dbSShawn McCarney };
107adc4f0dbSShawn McCarney 
108adc4f0dbSShawn McCarney /**
109413961deSRichard Marian Thomaiyar  * @brief Get objects with connection necessary for sensors
110588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp Pointer to object holding response data
11108777fb0SLewanczyk, Dawid  * @param sensorNames Sensors retrieved from chassis
11208777fb0SLewanczyk, Dawid  * @param callback Callback for processing gathered connections
11308777fb0SLewanczyk, Dawid  */
11408777fb0SLewanczyk, Dawid template <typename Callback>
115413961deSRichard Marian Thomaiyar void getObjectsWithConnection(
116413961deSRichard Marian Thomaiyar     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
11749c53ac9SJohnathan Mantey     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
1181abe55efSEd Tanous     Callback&& callback)
1191abe55efSEd Tanous {
120413961deSRichard Marian Thomaiyar     BMCWEB_LOG_DEBUG << "getObjectsWithConnection enter";
12103b5bae3SJames Feist     const std::string path = "/xyz/openbmc_project/sensors";
12208777fb0SLewanczyk, Dawid     const std::array<std::string, 1> interfaces = {
12308777fb0SLewanczyk, Dawid         "xyz.openbmc_project.Sensor.Value"};
12408777fb0SLewanczyk, Dawid 
12508777fb0SLewanczyk, Dawid     // Response handler for parsing objects subtree
1261abe55efSEd Tanous     auto respHandler = [callback{std::move(callback)}, SensorsAsyncResp,
1271abe55efSEd Tanous                         sensorNames](const boost::system::error_code ec,
1281abe55efSEd Tanous                                      const GetSubTreeType& subtree) {
129413961deSRichard Marian Thomaiyar         BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler enter";
1301abe55efSEd Tanous         if (ec)
1311abe55efSEd Tanous         {
1325f7d88c4SEd Tanous             messages::internalError(SensorsAsyncResp->res);
133413961deSRichard Marian Thomaiyar             BMCWEB_LOG_ERROR
134413961deSRichard Marian Thomaiyar                 << "getObjectsWithConnection resp_handler: Dbus error " << ec;
13508777fb0SLewanczyk, Dawid             return;
13608777fb0SLewanczyk, Dawid         }
13708777fb0SLewanczyk, Dawid 
13855c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
13908777fb0SLewanczyk, Dawid 
14008777fb0SLewanczyk, Dawid         // Make unique list of connections only for requested sensor types and
14108777fb0SLewanczyk, Dawid         // found in the chassis
14208777fb0SLewanczyk, Dawid         boost::container::flat_set<std::string> connections;
143413961deSRichard Marian Thomaiyar         std::set<std::pair<std::string, std::string>> objectsWithConnection;
1441abe55efSEd Tanous         // Intrinsic to avoid malloc.  Most systems will have < 8 sensor
1451abe55efSEd Tanous         // producers
14608777fb0SLewanczyk, Dawid         connections.reserve(8);
14708777fb0SLewanczyk, Dawid 
14849c53ac9SJohnathan Mantey         BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames->size();
14949c53ac9SJohnathan Mantey         for (const std::string& tsensor : *sensorNames)
1501abe55efSEd Tanous         {
15155c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor;
15208777fb0SLewanczyk, Dawid         }
15308777fb0SLewanczyk, Dawid 
15408777fb0SLewanczyk, Dawid         for (const std::pair<
15508777fb0SLewanczyk, Dawid                  std::string,
15608777fb0SLewanczyk, Dawid                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
1571abe55efSEd Tanous                  object : subtree)
1581abe55efSEd Tanous         {
15949c53ac9SJohnathan Mantey             if (sensorNames->find(object.first) != sensorNames->end())
1601abe55efSEd Tanous             {
16149c53ac9SJohnathan Mantey                 for (const std::pair<std::string, std::vector<std::string>>&
1621abe55efSEd Tanous                          objData : object.second)
1631abe55efSEd Tanous                 {
16449c53ac9SJohnathan Mantey                     BMCWEB_LOG_DEBUG << "Adding connection: " << objData.first;
16508777fb0SLewanczyk, Dawid                     connections.insert(objData.first);
166de629b6eSShawn McCarney                     objectsWithConnection.insert(
167de629b6eSShawn McCarney                         std::make_pair(object.first, objData.first));
16808777fb0SLewanczyk, Dawid                 }
16908777fb0SLewanczyk, Dawid             }
17008777fb0SLewanczyk, Dawid         }
17155c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections";
172413961deSRichard Marian Thomaiyar         callback(std::move(connections), std::move(objectsWithConnection));
173413961deSRichard Marian Thomaiyar         BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler exit";
17408777fb0SLewanczyk, Dawid     };
17508777fb0SLewanczyk, Dawid     // Make call to ObjectMapper to find all sensors objects
17655c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
17755c7b7a2SEd Tanous         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
1781abe55efSEd Tanous         "/xyz/openbmc_project/object_mapper",
1791abe55efSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 2, interfaces);
180413961deSRichard Marian Thomaiyar     BMCWEB_LOG_DEBUG << "getObjectsWithConnection exit";
181413961deSRichard Marian Thomaiyar }
182413961deSRichard Marian Thomaiyar 
183413961deSRichard Marian Thomaiyar /**
184413961deSRichard Marian Thomaiyar  * @brief Create connections necessary for sensors
185413961deSRichard Marian Thomaiyar  * @param SensorsAsyncResp Pointer to object holding response data
186413961deSRichard Marian Thomaiyar  * @param sensorNames Sensors retrieved from chassis
187413961deSRichard Marian Thomaiyar  * @param callback Callback for processing gathered connections
188413961deSRichard Marian Thomaiyar  */
189413961deSRichard Marian Thomaiyar template <typename Callback>
19049c53ac9SJohnathan Mantey void getConnections(
19149c53ac9SJohnathan Mantey     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
19249c53ac9SJohnathan Mantey     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
193413961deSRichard Marian Thomaiyar     Callback&& callback)
194413961deSRichard Marian Thomaiyar {
195413961deSRichard Marian Thomaiyar     auto objectsWithConnectionCb =
196413961deSRichard Marian Thomaiyar         [callback](const boost::container::flat_set<std::string>& connections,
197413961deSRichard Marian Thomaiyar                    const std::set<std::pair<std::string, std::string>>&
198413961deSRichard Marian Thomaiyar                        objectsWithConnection) {
199413961deSRichard Marian Thomaiyar             callback(std::move(connections));
200413961deSRichard Marian Thomaiyar         };
201413961deSRichard Marian Thomaiyar     getObjectsWithConnection(SensorsAsyncResp, sensorNames,
202413961deSRichard Marian Thomaiyar                              std::move(objectsWithConnectionCb));
20308777fb0SLewanczyk, Dawid }
20408777fb0SLewanczyk, Dawid 
20508777fb0SLewanczyk, Dawid /**
20649c53ac9SJohnathan Mantey  * @brief Shrinks the list of sensors for processing
20749c53ac9SJohnathan Mantey  * @param SensorsAysncResp  The class holding the Redfish response
20849c53ac9SJohnathan Mantey  * @param allSensors  A list of all the sensors associated to the
20949c53ac9SJohnathan Mantey  * chassis element (i.e. baseboard, front panel, etc...)
21049c53ac9SJohnathan Mantey  * @param activeSensors A list that is a reduction of the incoming
21149c53ac9SJohnathan Mantey  * allSensors list.  Eliminate Thermal sensors when a Power request is
21249c53ac9SJohnathan Mantey  * made, and eliminate Power sensors when a Thermal request is made.
21349c53ac9SJohnathan Mantey  */
21449c53ac9SJohnathan Mantey void reduceSensorList(
21549c53ac9SJohnathan Mantey     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
21649c53ac9SJohnathan Mantey     const std::vector<std::string>* allSensors,
21749c53ac9SJohnathan Mantey     std::shared_ptr<boost::container::flat_set<std::string>> activeSensors)
21849c53ac9SJohnathan Mantey {
21949c53ac9SJohnathan Mantey     if (SensorsAsyncResp == nullptr)
22049c53ac9SJohnathan Mantey     {
22149c53ac9SJohnathan Mantey         return;
22249c53ac9SJohnathan Mantey     }
22349c53ac9SJohnathan Mantey     if ((allSensors == nullptr) || (activeSensors == nullptr))
22449c53ac9SJohnathan Mantey     {
22549c53ac9SJohnathan Mantey         messages::resourceNotFound(
22649c53ac9SJohnathan Mantey             SensorsAsyncResp->res, SensorsAsyncResp->chassisSubNode,
22749c53ac9SJohnathan Mantey             SensorsAsyncResp->chassisSubNode == "Thermal" ? "Temperatures"
22849c53ac9SJohnathan Mantey                                                           : "Voltages");
22949c53ac9SJohnathan Mantey 
23049c53ac9SJohnathan Mantey         return;
23149c53ac9SJohnathan Mantey     }
23249c53ac9SJohnathan Mantey     if (allSensors->empty())
23349c53ac9SJohnathan Mantey     {
23449c53ac9SJohnathan Mantey         // Nothing to do, the activeSensors object is also empty
23549c53ac9SJohnathan Mantey         return;
23649c53ac9SJohnathan Mantey     }
23749c53ac9SJohnathan Mantey 
23849c53ac9SJohnathan Mantey     for (const char* type : SensorsAsyncResp->types)
23949c53ac9SJohnathan Mantey     {
24049c53ac9SJohnathan Mantey         for (const std::string& sensor : *allSensors)
24149c53ac9SJohnathan Mantey         {
24249c53ac9SJohnathan Mantey             if (boost::starts_with(sensor, type))
24349c53ac9SJohnathan Mantey             {
24449c53ac9SJohnathan Mantey                 activeSensors->emplace(sensor);
24549c53ac9SJohnathan Mantey             }
24649c53ac9SJohnathan Mantey         }
24749c53ac9SJohnathan Mantey     }
24849c53ac9SJohnathan Mantey }
24949c53ac9SJohnathan Mantey 
25049c53ac9SJohnathan Mantey /**
25108777fb0SLewanczyk, Dawid  * @brief Retrieves requested chassis sensors and redundancy data from DBus .
252588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
25308777fb0SLewanczyk, Dawid  * @param callback  Callback for next step in gathered sensor processing
25408777fb0SLewanczyk, Dawid  */
25508777fb0SLewanczyk, Dawid template <typename Callback>
25649c53ac9SJohnathan Mantey void getChassis(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
2571abe55efSEd Tanous                 Callback&& callback)
2581abe55efSEd Tanous {
25955c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis enter";
260adc4f0dbSShawn McCarney     const std::array<const char*, 2> interfaces = {
26149c53ac9SJohnathan Mantey         "xyz.openbmc_project.Inventory.Item.Board",
262adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Item.Chassis"};
26349c53ac9SJohnathan Mantey     auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp](
26449c53ac9SJohnathan Mantey                            const boost::system::error_code ec,
26549c53ac9SJohnathan Mantey                            const std::vector<std::string>& chassisPaths) {
26655c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassis respHandler enter";
2671abe55efSEd Tanous         if (ec)
2681abe55efSEd Tanous         {
26955c7b7a2SEd Tanous             BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec;
27049c53ac9SJohnathan Mantey             messages::internalError(sensorsAsyncResp->res);
27108777fb0SLewanczyk, Dawid             return;
27208777fb0SLewanczyk, Dawid         }
27308777fb0SLewanczyk, Dawid 
27449c53ac9SJohnathan Mantey         const std::string* chassisPath = nullptr;
27549c53ac9SJohnathan Mantey         std::string chassisName;
27649c53ac9SJohnathan Mantey         for (const std::string& chassis : chassisPaths)
2771abe55efSEd Tanous         {
27849c53ac9SJohnathan Mantey             std::size_t lastPos = chassis.rfind("/");
27949c53ac9SJohnathan Mantey             if (lastPos == std::string::npos)
2801abe55efSEd Tanous             {
28149c53ac9SJohnathan Mantey                 BMCWEB_LOG_ERROR << "Failed to find '/' in " << chassis;
282daf36e2eSEd Tanous                 continue;
283daf36e2eSEd Tanous             }
28449c53ac9SJohnathan Mantey             chassisName = chassis.substr(lastPos + 1);
28549c53ac9SJohnathan Mantey             if (chassisName == sensorsAsyncResp->chassisId)
2861abe55efSEd Tanous             {
28749c53ac9SJohnathan Mantey                 chassisPath = &chassis;
28849c53ac9SJohnathan Mantey                 break;
289daf36e2eSEd Tanous             }
29049c53ac9SJohnathan Mantey         }
29149c53ac9SJohnathan Mantey         if (chassisPath == nullptr)
2921abe55efSEd Tanous         {
29349c53ac9SJohnathan Mantey             messages::resourceNotFound(sensorsAsyncResp->res, "Chassis",
29449c53ac9SJohnathan Mantey                                        sensorsAsyncResp->chassisId);
29549c53ac9SJohnathan Mantey             return;
2961abe55efSEd Tanous         }
29708777fb0SLewanczyk, Dawid 
29849c53ac9SJohnathan Mantey         const std::string& chassisSubNode = sensorsAsyncResp->chassisSubNode;
29949c53ac9SJohnathan Mantey         if (chassisSubNode == "Power")
30049c53ac9SJohnathan Mantey         {
30149c53ac9SJohnathan Mantey             sensorsAsyncResp->res.jsonValue["@odata.type"] =
30249c53ac9SJohnathan Mantey                 "#Power.v1_5_2.Power";
30349c53ac9SJohnathan Mantey         }
30449c53ac9SJohnathan Mantey         else if (chassisSubNode == "Thermal")
30549c53ac9SJohnathan Mantey         {
30649c53ac9SJohnathan Mantey             sensorsAsyncResp->res.jsonValue["@odata.type"] =
30749c53ac9SJohnathan Mantey                 "#Thermal.v1_4_0.Thermal";
3084f9a2130SJennifer Lee             sensorsAsyncResp->res.jsonValue["Fans"] = nlohmann::json::array();
3094f9a2130SJennifer Lee             sensorsAsyncResp->res.jsonValue["Temperatures"] =
3104f9a2130SJennifer Lee                 nlohmann::json::array();
31149c53ac9SJohnathan Mantey         }
31295a3ecadSAnthony Wilson         else if (chassisSubNode == "Sensors")
31395a3ecadSAnthony Wilson         {
31495a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["@odata.type"] =
31595a3ecadSAnthony Wilson                 "#SensorCollection.SensorCollection";
31695a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["@odata.context"] =
31795a3ecadSAnthony Wilson                 "/redfish/v1/$metadata#SensorCollection.SensorCollection";
31895a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["Description"] =
31995a3ecadSAnthony Wilson                 "Collection of Sensors for this Chassis";
32095a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["Members"] =
32195a3ecadSAnthony Wilson                 nlohmann::json::array();
32295a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["Members@odata.count"] = 0;
32395a3ecadSAnthony Wilson         }
32495a3ecadSAnthony Wilson 
32595a3ecadSAnthony Wilson         if (chassisSubNode != "Sensors")
32695a3ecadSAnthony Wilson         {
32795a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["Id"] = chassisSubNode;
32895a3ecadSAnthony Wilson             sensorsAsyncResp->res.jsonValue["@odata.context"] =
32995a3ecadSAnthony Wilson                 "/redfish/v1/$metadata#" + chassisSubNode + "." +
33095a3ecadSAnthony Wilson                 chassisSubNode;
33195a3ecadSAnthony Wilson         }
33295a3ecadSAnthony Wilson 
33349c53ac9SJohnathan Mantey         sensorsAsyncResp->res.jsonValue["@odata.id"] =
33449c53ac9SJohnathan Mantey             "/redfish/v1/Chassis/" + sensorsAsyncResp->chassisId + "/" +
33549c53ac9SJohnathan Mantey             chassisSubNode;
33649c53ac9SJohnathan Mantey         sensorsAsyncResp->res.jsonValue["Name"] = chassisSubNode;
33749c53ac9SJohnathan Mantey 
3388fb49dd6SShawn McCarney         // Get the list of all sensors for this Chassis element
3398fb49dd6SShawn McCarney         std::string sensorPath = *chassisPath + "/all_sensors";
34055c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
34149c53ac9SJohnathan Mantey             [sensorsAsyncResp, callback{std::move(callback)}](
342271584abSEd Tanous                 const boost::system::error_code& e,
34349c53ac9SJohnathan Mantey                 const std::variant<std::vector<std::string>>&
34449c53ac9SJohnathan Mantey                     variantEndpoints) {
345271584abSEd Tanous                 if (e)
34649c53ac9SJohnathan Mantey                 {
347271584abSEd Tanous                     if (e.value() != EBADR)
34849c53ac9SJohnathan Mantey                     {
34949c53ac9SJohnathan Mantey                         messages::internalError(sensorsAsyncResp->res);
35049c53ac9SJohnathan Mantey                         return;
35149c53ac9SJohnathan Mantey                     }
35249c53ac9SJohnathan Mantey                 }
35349c53ac9SJohnathan Mantey                 const std::vector<std::string>* nodeSensorList =
35449c53ac9SJohnathan Mantey                     std::get_if<std::vector<std::string>>(&(variantEndpoints));
35549c53ac9SJohnathan Mantey                 if (nodeSensorList == nullptr)
35649c53ac9SJohnathan Mantey                 {
35749c53ac9SJohnathan Mantey                     messages::resourceNotFound(
35849c53ac9SJohnathan Mantey                         sensorsAsyncResp->res, sensorsAsyncResp->chassisSubNode,
35949c53ac9SJohnathan Mantey                         sensorsAsyncResp->chassisSubNode == "Thermal"
36049c53ac9SJohnathan Mantey                             ? "Temperatures"
36195a3ecadSAnthony Wilson                             : sensorsAsyncResp->chassisSubNode == "Power"
36295a3ecadSAnthony Wilson                                   ? "Voltages"
36395a3ecadSAnthony Wilson                                   : "Sensors");
36449c53ac9SJohnathan Mantey                     return;
36549c53ac9SJohnathan Mantey                 }
36649c53ac9SJohnathan Mantey                 const std::shared_ptr<boost::container::flat_set<std::string>>
36749c53ac9SJohnathan Mantey                     culledSensorList = std::make_shared<
36849c53ac9SJohnathan Mantey                         boost::container::flat_set<std::string>>();
36949c53ac9SJohnathan Mantey                 reduceSensorList(sensorsAsyncResp, nodeSensorList,
37049c53ac9SJohnathan Mantey                                  culledSensorList);
37149c53ac9SJohnathan Mantey                 callback(culledSensorList);
37249c53ac9SJohnathan Mantey             },
37349c53ac9SJohnathan Mantey             "xyz.openbmc_project.ObjectMapper", sensorPath,
37449c53ac9SJohnathan Mantey             "org.freedesktop.DBus.Properties", "Get",
37549c53ac9SJohnathan Mantey             "xyz.openbmc_project.Association", "endpoints");
37649c53ac9SJohnathan Mantey     };
37749c53ac9SJohnathan Mantey 
37849c53ac9SJohnathan Mantey     // Get the Chassis Collection
37949c53ac9SJohnathan Mantey     crow::connections::systemBus->async_method_call(
38049c53ac9SJohnathan Mantey         respHandler, "xyz.openbmc_project.ObjectMapper",
38149c53ac9SJohnathan Mantey         "/xyz/openbmc_project/object_mapper",
38249c53ac9SJohnathan Mantey         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
383271584abSEd Tanous         "/xyz/openbmc_project/inventory", 0, interfaces);
38455c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis exit";
38508777fb0SLewanczyk, Dawid }
38608777fb0SLewanczyk, Dawid 
38708777fb0SLewanczyk, Dawid /**
388de629b6eSShawn McCarney  * @brief Finds all DBus object paths that implement ObjectManager.
389de629b6eSShawn McCarney  *
390de629b6eSShawn McCarney  * Creates a mapping from the associated connection name to the object path.
391de629b6eSShawn McCarney  *
392de629b6eSShawn McCarney  * Finds the object paths asynchronously.  Invokes callback when information has
393de629b6eSShawn McCarney  * been obtained.
394de629b6eSShawn McCarney  *
395de629b6eSShawn McCarney  * The callback must have the following signature:
396de629b6eSShawn McCarney  *   @code
3978fb49dd6SShawn McCarney  *   callback(std::shared_ptr<boost::container::flat_map<std::string,
3988fb49dd6SShawn McCarney  *                std::string>> objectMgrPaths)
399de629b6eSShawn McCarney  *   @endcode
400de629b6eSShawn McCarney  *
40149c53ac9SJohnathan Mantey  * @param sensorsAsyncResp Pointer to object holding response data.
402de629b6eSShawn McCarney  * @param callback Callback to invoke when object paths obtained.
403de629b6eSShawn McCarney  */
404de629b6eSShawn McCarney template <typename Callback>
405de629b6eSShawn McCarney void getObjectManagerPaths(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
406de629b6eSShawn McCarney                            Callback&& callback)
407de629b6eSShawn McCarney {
408de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getObjectManagerPaths enter";
409de629b6eSShawn McCarney     const std::array<std::string, 1> interfaces = {
410de629b6eSShawn McCarney         "org.freedesktop.DBus.ObjectManager"};
411de629b6eSShawn McCarney 
412de629b6eSShawn McCarney     // Response handler for GetSubTree DBus method
413de629b6eSShawn McCarney     auto respHandler = [callback{std::move(callback)},
414de629b6eSShawn McCarney                         SensorsAsyncResp](const boost::system::error_code ec,
415de629b6eSShawn McCarney                                           const GetSubTreeType& subtree) {
416de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler enter";
417de629b6eSShawn McCarney         if (ec)
418de629b6eSShawn McCarney         {
419de629b6eSShawn McCarney             messages::internalError(SensorsAsyncResp->res);
420de629b6eSShawn McCarney             BMCWEB_LOG_ERROR << "getObjectManagerPaths respHandler: DBus error "
421de629b6eSShawn McCarney                              << ec;
422de629b6eSShawn McCarney             return;
423de629b6eSShawn McCarney         }
424de629b6eSShawn McCarney 
425de629b6eSShawn McCarney         // Loop over returned object paths
4268fb49dd6SShawn McCarney         std::shared_ptr<boost::container::flat_map<std::string, std::string>>
4278fb49dd6SShawn McCarney             objectMgrPaths = std::make_shared<
4288fb49dd6SShawn McCarney                 boost::container::flat_map<std::string, std::string>>();
429de629b6eSShawn McCarney         for (const std::pair<
430de629b6eSShawn McCarney                  std::string,
431de629b6eSShawn McCarney                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
432de629b6eSShawn McCarney                  object : subtree)
433de629b6eSShawn McCarney         {
434de629b6eSShawn McCarney             // Loop over connections for current object path
435de629b6eSShawn McCarney             const std::string& objectPath = object.first;
436de629b6eSShawn McCarney             for (const std::pair<std::string, std::vector<std::string>>&
437de629b6eSShawn McCarney                      objData : object.second)
438de629b6eSShawn McCarney             {
439de629b6eSShawn McCarney                 // Add mapping from connection to object path
440de629b6eSShawn McCarney                 const std::string& connection = objData.first;
4418fb49dd6SShawn McCarney                 (*objectMgrPaths)[connection] = objectPath;
442de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "Added mapping " << connection << " -> "
443de629b6eSShawn McCarney                                  << objectPath;
444de629b6eSShawn McCarney             }
445de629b6eSShawn McCarney         }
4468fb49dd6SShawn McCarney         callback(objectMgrPaths);
447de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler exit";
448de629b6eSShawn McCarney     };
449de629b6eSShawn McCarney 
450de629b6eSShawn McCarney     // Query mapper for all DBus object paths that implement ObjectManager
451de629b6eSShawn McCarney     crow::connections::systemBus->async_method_call(
452de629b6eSShawn McCarney         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
453de629b6eSShawn McCarney         "/xyz/openbmc_project/object_mapper",
454271584abSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, interfaces);
455de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getObjectManagerPaths exit";
456de629b6eSShawn McCarney }
457de629b6eSShawn McCarney 
458de629b6eSShawn McCarney /**
459adc4f0dbSShawn McCarney  * @brief Returns the Redfish State value for the specified inventory item.
460adc4f0dbSShawn McCarney  * @param inventoryItem D-Bus inventory item associated with a sensor.
461adc4f0dbSShawn McCarney  * @return State value for inventory item.
46234dd179eSJames Feist  */
463adc4f0dbSShawn McCarney static std::string getState(const InventoryItem* inventoryItem)
464adc4f0dbSShawn McCarney {
465adc4f0dbSShawn McCarney     if ((inventoryItem != nullptr) && !(inventoryItem->isPresent))
466adc4f0dbSShawn McCarney     {
467adc4f0dbSShawn McCarney         return "Absent";
468adc4f0dbSShawn McCarney     }
46934dd179eSJames Feist 
470adc4f0dbSShawn McCarney     return "Enabled";
471adc4f0dbSShawn McCarney }
472adc4f0dbSShawn McCarney 
473adc4f0dbSShawn McCarney /**
474adc4f0dbSShawn McCarney  * @brief Returns the Redfish Health value for the specified sensor.
475adc4f0dbSShawn McCarney  * @param sensorJson Sensor JSON object.
476adc4f0dbSShawn McCarney  * @param interfacesDict Map of all sensor interfaces.
477adc4f0dbSShawn McCarney  * @param inventoryItem D-Bus inventory item associated with the sensor.  Will
478adc4f0dbSShawn McCarney  * be nullptr if no associated inventory item was found.
479adc4f0dbSShawn McCarney  * @return Health value for sensor.
480adc4f0dbSShawn McCarney  */
48134dd179eSJames Feist static std::string getHealth(
482adc4f0dbSShawn McCarney     nlohmann::json& sensorJson,
48334dd179eSJames Feist     const boost::container::flat_map<
48434dd179eSJames Feist         std::string, boost::container::flat_map<std::string, SensorVariant>>&
485adc4f0dbSShawn McCarney         interfacesDict,
486adc4f0dbSShawn McCarney     const InventoryItem* inventoryItem)
48734dd179eSJames Feist {
488adc4f0dbSShawn McCarney     // Get current health value (if any) in the sensor JSON object.  Some JSON
489adc4f0dbSShawn McCarney     // objects contain multiple sensors (such as PowerSupplies).  We want to set
490adc4f0dbSShawn McCarney     // the overall health to be the most severe of any of the sensors.
491adc4f0dbSShawn McCarney     std::string currentHealth;
492adc4f0dbSShawn McCarney     auto statusIt = sensorJson.find("Status");
493adc4f0dbSShawn McCarney     if (statusIt != sensorJson.end())
494adc4f0dbSShawn McCarney     {
495adc4f0dbSShawn McCarney         auto healthIt = statusIt->find("Health");
496adc4f0dbSShawn McCarney         if (healthIt != statusIt->end())
497adc4f0dbSShawn McCarney         {
498adc4f0dbSShawn McCarney             std::string* health = healthIt->get_ptr<std::string*>();
499adc4f0dbSShawn McCarney             if (health != nullptr)
500adc4f0dbSShawn McCarney             {
501adc4f0dbSShawn McCarney                 currentHealth = *health;
502adc4f0dbSShawn McCarney             }
503adc4f0dbSShawn McCarney         }
504adc4f0dbSShawn McCarney     }
505adc4f0dbSShawn McCarney 
506adc4f0dbSShawn McCarney     // If current health in JSON object is already Critical, return that.  This
507adc4f0dbSShawn McCarney     // should override the sensor health, which might be less severe.
508adc4f0dbSShawn McCarney     if (currentHealth == "Critical")
509adc4f0dbSShawn McCarney     {
510adc4f0dbSShawn McCarney         return "Critical";
511adc4f0dbSShawn McCarney     }
512adc4f0dbSShawn McCarney 
513adc4f0dbSShawn McCarney     // Check if sensor has critical threshold alarm
51434dd179eSJames Feist     auto criticalThresholdIt =
51534dd179eSJames Feist         interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Critical");
51634dd179eSJames Feist     if (criticalThresholdIt != interfacesDict.end())
51734dd179eSJames Feist     {
51834dd179eSJames Feist         auto thresholdHighIt =
51934dd179eSJames Feist             criticalThresholdIt->second.find("CriticalAlarmHigh");
52034dd179eSJames Feist         auto thresholdLowIt =
52134dd179eSJames Feist             criticalThresholdIt->second.find("CriticalAlarmLow");
52234dd179eSJames Feist         if (thresholdHighIt != criticalThresholdIt->second.end())
52334dd179eSJames Feist         {
52434dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdHighIt->second);
52534dd179eSJames Feist             if (asserted == nullptr)
52634dd179eSJames Feist             {
52734dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
52834dd179eSJames Feist             }
52934dd179eSJames Feist             else if (*asserted)
53034dd179eSJames Feist             {
53134dd179eSJames Feist                 return "Critical";
53234dd179eSJames Feist             }
53334dd179eSJames Feist         }
53434dd179eSJames Feist         if (thresholdLowIt != criticalThresholdIt->second.end())
53534dd179eSJames Feist         {
53634dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdLowIt->second);
53734dd179eSJames Feist             if (asserted == nullptr)
53834dd179eSJames Feist             {
53934dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
54034dd179eSJames Feist             }
54134dd179eSJames Feist             else if (*asserted)
54234dd179eSJames Feist             {
54334dd179eSJames Feist                 return "Critical";
54434dd179eSJames Feist             }
54534dd179eSJames Feist         }
54634dd179eSJames Feist     }
54734dd179eSJames Feist 
548adc4f0dbSShawn McCarney     // Check if associated inventory item is not functional
549adc4f0dbSShawn McCarney     if ((inventoryItem != nullptr) && !(inventoryItem->isFunctional))
550adc4f0dbSShawn McCarney     {
551adc4f0dbSShawn McCarney         return "Critical";
552adc4f0dbSShawn McCarney     }
553adc4f0dbSShawn McCarney 
554adc4f0dbSShawn McCarney     // If current health in JSON object is already Warning, return that.  This
555adc4f0dbSShawn McCarney     // should override the sensor status, which might be less severe.
556adc4f0dbSShawn McCarney     if (currentHealth == "Warning")
557adc4f0dbSShawn McCarney     {
558adc4f0dbSShawn McCarney         return "Warning";
559adc4f0dbSShawn McCarney     }
560adc4f0dbSShawn McCarney 
561adc4f0dbSShawn McCarney     // Check if sensor has warning threshold alarm
56234dd179eSJames Feist     auto warningThresholdIt =
56334dd179eSJames Feist         interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Warning");
56434dd179eSJames Feist     if (warningThresholdIt != interfacesDict.end())
56534dd179eSJames Feist     {
56634dd179eSJames Feist         auto thresholdHighIt =
56734dd179eSJames Feist             warningThresholdIt->second.find("WarningAlarmHigh");
56834dd179eSJames Feist         auto thresholdLowIt =
56934dd179eSJames Feist             warningThresholdIt->second.find("WarningAlarmLow");
57034dd179eSJames Feist         if (thresholdHighIt != warningThresholdIt->second.end())
57134dd179eSJames Feist         {
57234dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdHighIt->second);
57334dd179eSJames Feist             if (asserted == nullptr)
57434dd179eSJames Feist             {
57534dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
57634dd179eSJames Feist             }
57734dd179eSJames Feist             else if (*asserted)
57834dd179eSJames Feist             {
57934dd179eSJames Feist                 return "Warning";
58034dd179eSJames Feist             }
58134dd179eSJames Feist         }
58234dd179eSJames Feist         if (thresholdLowIt != warningThresholdIt->second.end())
58334dd179eSJames Feist         {
58434dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdLowIt->second);
58534dd179eSJames Feist             if (asserted == nullptr)
58634dd179eSJames Feist             {
58734dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
58834dd179eSJames Feist             }
58934dd179eSJames Feist             else if (*asserted)
59034dd179eSJames Feist             {
59134dd179eSJames Feist                 return "Warning";
59234dd179eSJames Feist             }
59334dd179eSJames Feist         }
59434dd179eSJames Feist     }
595adc4f0dbSShawn McCarney 
59634dd179eSJames Feist     return "OK";
59734dd179eSJames Feist }
59834dd179eSJames Feist 
59934dd179eSJames Feist /**
60008777fb0SLewanczyk, Dawid  * @brief Builds a json sensor representation of a sensor.
60108777fb0SLewanczyk, Dawid  * @param sensorName  The name of the sensor to be built
602274fad5aSGunnar Mills  * @param sensorType  The type (temperature, fan_tach, etc) of the sensor to
60308777fb0SLewanczyk, Dawid  * build
60495a3ecadSAnthony Wilson  * @param sensorSchema  The schema (Power, Thermal, etc) being associated with
60595a3ecadSAnthony Wilson  * the sensor to build
60608777fb0SLewanczyk, Dawid  * @param interfacesDict  A dictionary of the interfaces and properties of said
60708777fb0SLewanczyk, Dawid  * interfaces to be built from
60808777fb0SLewanczyk, Dawid  * @param sensor_json  The json object to fill
609adc4f0dbSShawn McCarney  * @param inventoryItem D-Bus inventory item associated with the sensor.  Will
610adc4f0dbSShawn McCarney  * be nullptr if no associated inventory item was found.
61108777fb0SLewanczyk, Dawid  */
61208777fb0SLewanczyk, Dawid void objectInterfacesToJson(
61308777fb0SLewanczyk, Dawid     const std::string& sensorName, const std::string& sensorType,
61495a3ecadSAnthony Wilson     const std::string& sensorSchema,
61508777fb0SLewanczyk, Dawid     const boost::container::flat_map<
616aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>&
61708777fb0SLewanczyk, Dawid         interfacesDict,
618adc4f0dbSShawn McCarney     nlohmann::json& sensor_json, InventoryItem* inventoryItem)
6191abe55efSEd Tanous {
62008777fb0SLewanczyk, Dawid     // We need a value interface before we can do anything with it
62155c7b7a2SEd Tanous     auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
6221abe55efSEd Tanous     if (valueIt == interfacesDict.end())
6231abe55efSEd Tanous     {
62455c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface";
62508777fb0SLewanczyk, Dawid         return;
62608777fb0SLewanczyk, Dawid     }
62708777fb0SLewanczyk, Dawid 
62808777fb0SLewanczyk, Dawid     // Assume values exist as is (10^0 == 1) if no scale exists
62908777fb0SLewanczyk, Dawid     int64_t scaleMultiplier = 0;
63008777fb0SLewanczyk, Dawid 
63155c7b7a2SEd Tanous     auto scaleIt = valueIt->second.find("Scale");
63208777fb0SLewanczyk, Dawid     // If a scale exists, pull value as int64, and use the scaling.
6331abe55efSEd Tanous     if (scaleIt != valueIt->second.end())
6341abe55efSEd Tanous     {
635abf2add6SEd Tanous         const int64_t* int64Value = std::get_if<int64_t>(&scaleIt->second);
6361abe55efSEd Tanous         if (int64Value != nullptr)
6371abe55efSEd Tanous         {
63808777fb0SLewanczyk, Dawid             scaleMultiplier = *int64Value;
63908777fb0SLewanczyk, Dawid         }
64008777fb0SLewanczyk, Dawid     }
64108777fb0SLewanczyk, Dawid 
64295a3ecadSAnthony Wilson     if (sensorSchema == "Sensors")
643adc4f0dbSShawn McCarney     {
64495a3ecadSAnthony Wilson         // For sensors in SensorCollection we set Id instead of MemberId,
64595a3ecadSAnthony Wilson         // including power sensors.
64695a3ecadSAnthony Wilson         sensor_json["Id"] = sensorName;
64795a3ecadSAnthony Wilson         sensor_json["Name"] = boost::replace_all_copy(sensorName, "_", " ");
64895a3ecadSAnthony Wilson     }
64995a3ecadSAnthony Wilson     else if (sensorType != "power")
65095a3ecadSAnthony Wilson     {
65195a3ecadSAnthony Wilson         // Set MemberId and Name for non-power sensors.  For PowerSupplies and
65295a3ecadSAnthony Wilson         // PowerControl, those properties have more general values because
65395a3ecadSAnthony Wilson         // multiple sensors can be stored in the same JSON object.
65408777fb0SLewanczyk, Dawid         sensor_json["MemberId"] = sensorName;
655e742b6ccSEd Tanous         sensor_json["Name"] = boost::replace_all_copy(sensorName, "_", " ");
656adc4f0dbSShawn McCarney     }
657e742b6ccSEd Tanous 
658adc4f0dbSShawn McCarney     sensor_json["Status"]["State"] = getState(inventoryItem);
659adc4f0dbSShawn McCarney     sensor_json["Status"]["Health"] =
660adc4f0dbSShawn McCarney         getHealth(sensor_json, interfacesDict, inventoryItem);
66108777fb0SLewanczyk, Dawid 
66208777fb0SLewanczyk, Dawid     // Parameter to set to override the type we get from dbus, and force it to
66308777fb0SLewanczyk, Dawid     // int, regardless of what is available.  This is used for schemas like fan,
66408777fb0SLewanczyk, Dawid     // that require integers, not floats.
66508777fb0SLewanczyk, Dawid     bool forceToInt = false;
66608777fb0SLewanczyk, Dawid 
6673929aca1SAnthony Wilson     nlohmann::json::json_pointer unit("/Reading");
66895a3ecadSAnthony Wilson     if (sensorSchema == "Sensors")
66995a3ecadSAnthony Wilson     {
67095a3ecadSAnthony Wilson         sensor_json["@odata.type"] = "#Sensor.v1_0_0.Sensor";
67195a3ecadSAnthony Wilson         sensor_json["@odata.context"] = "/redfish/v1/$metadata#Sensor.Sensor";
67295a3ecadSAnthony Wilson         if (sensorType == "power")
67395a3ecadSAnthony Wilson         {
67495a3ecadSAnthony Wilson             sensor_json["ReadingUnits"] = "Watts";
67595a3ecadSAnthony Wilson         }
67695a3ecadSAnthony Wilson         else if (sensorType == "current")
67795a3ecadSAnthony Wilson         {
67895a3ecadSAnthony Wilson             sensor_json["ReadingUnits"] = "Amperes";
67995a3ecadSAnthony Wilson         }
68095a3ecadSAnthony Wilson     }
68195a3ecadSAnthony Wilson     else if (sensorType == "temperature")
6821abe55efSEd Tanous     {
6833929aca1SAnthony Wilson         unit = "/ReadingCelsius"_json_pointer;
6847885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature";
68508777fb0SLewanczyk, Dawid         // TODO(ed) Documentation says that path should be type fan_tach,
68608777fb0SLewanczyk, Dawid         // implementation seems to implement fan
6871abe55efSEd Tanous     }
6881abe55efSEd Tanous     else if (sensorType == "fan" || sensorType == "fan_tach")
6891abe55efSEd Tanous     {
6903929aca1SAnthony Wilson         unit = "/Reading"_json_pointer;
69108777fb0SLewanczyk, Dawid         sensor_json["ReadingUnits"] = "RPM";
6927885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
69308777fb0SLewanczyk, Dawid         forceToInt = true;
6941abe55efSEd Tanous     }
6956f6d0d32SEd Tanous     else if (sensorType == "fan_pwm")
6966f6d0d32SEd Tanous     {
6973929aca1SAnthony Wilson         unit = "/Reading"_json_pointer;
6986f6d0d32SEd Tanous         sensor_json["ReadingUnits"] = "Percent";
6996f6d0d32SEd Tanous         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
7006f6d0d32SEd Tanous         forceToInt = true;
7016f6d0d32SEd Tanous     }
7021abe55efSEd Tanous     else if (sensorType == "voltage")
7031abe55efSEd Tanous     {
7043929aca1SAnthony Wilson         unit = "/ReadingVolts"_json_pointer;
7057885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage";
7061abe55efSEd Tanous     }
7072474adfaSEd Tanous     else if (sensorType == "power")
7082474adfaSEd Tanous     {
70949c53ac9SJohnathan Mantey         std::string sensorNameLower =
71049c53ac9SJohnathan Mantey             boost::algorithm::to_lower_copy(sensorName);
71149c53ac9SJohnathan Mantey 
712028f7ebcSEddie James         if (!sensorName.compare("total_power"))
713028f7ebcSEddie James         {
7147ab06f49SGunnar Mills             sensor_json["@odata.type"] = "#Power.v1_0_0.PowerControl";
7157ab06f49SGunnar Mills             // Put multiple "sensors" into a single PowerControl, so have
7167ab06f49SGunnar Mills             // generic names for MemberId and Name. Follows Redfish mockup.
7177ab06f49SGunnar Mills             sensor_json["MemberId"] = "0";
7187ab06f49SGunnar Mills             sensor_json["Name"] = "Chassis Power Control";
7193929aca1SAnthony Wilson             unit = "/PowerConsumedWatts"_json_pointer;
720028f7ebcSEddie James         }
721028f7ebcSEddie James         else if (sensorNameLower.find("input") != std::string::npos)
72249c53ac9SJohnathan Mantey         {
7233929aca1SAnthony Wilson             unit = "/PowerInputWatts"_json_pointer;
72449c53ac9SJohnathan Mantey         }
72549c53ac9SJohnathan Mantey         else
72649c53ac9SJohnathan Mantey         {
7273929aca1SAnthony Wilson             unit = "/PowerOutputWatts"_json_pointer;
72849c53ac9SJohnathan Mantey         }
7292474adfaSEd Tanous     }
7301abe55efSEd Tanous     else
7311abe55efSEd Tanous     {
73255c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
73308777fb0SLewanczyk, Dawid         return;
73408777fb0SLewanczyk, Dawid     }
73508777fb0SLewanczyk, Dawid     // Map of dbus interface name, dbus property name and redfish property_name
7363929aca1SAnthony Wilson     std::vector<
7373929aca1SAnthony Wilson         std::tuple<const char*, const char*, nlohmann::json::json_pointer>>
7383929aca1SAnthony Wilson         properties;
73908777fb0SLewanczyk, Dawid     properties.reserve(7);
74008777fb0SLewanczyk, Dawid 
74108777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
742de629b6eSShawn McCarney 
7433929aca1SAnthony Wilson     if (sensorSchema == "Sensors")
7443929aca1SAnthony Wilson     {
7453929aca1SAnthony Wilson         properties.emplace_back(
7463929aca1SAnthony Wilson             "xyz.openbmc_project.Sensor.Threshold.Warning", "WarningHigh",
7473929aca1SAnthony Wilson             "/Thresholds/UpperCaution/Reading"_json_pointer);
7483929aca1SAnthony Wilson         properties.emplace_back(
7493929aca1SAnthony Wilson             "xyz.openbmc_project.Sensor.Threshold.Warning", "WarningLow",
7503929aca1SAnthony Wilson             "/Thresholds/LowerCaution/Reading"_json_pointer);
7513929aca1SAnthony Wilson         properties.emplace_back(
7523929aca1SAnthony Wilson             "xyz.openbmc_project.Sensor.Threshold.Critical", "CriticalHigh",
7533929aca1SAnthony Wilson             "/Thresholds/UpperCritical/Reading"_json_pointer);
7543929aca1SAnthony Wilson         properties.emplace_back(
7553929aca1SAnthony Wilson             "xyz.openbmc_project.Sensor.Threshold.Critical", "CriticalLow",
7563929aca1SAnthony Wilson             "/Thresholds/LowerCritical/Reading"_json_pointer);
7573929aca1SAnthony Wilson     }
7583929aca1SAnthony Wilson     else if (sensorType != "power")
759de629b6eSShawn McCarney     {
76008777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
7613929aca1SAnthony Wilson                                 "WarningHigh",
7623929aca1SAnthony Wilson                                 "/UpperThresholdNonCritical"_json_pointer);
76308777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
7643929aca1SAnthony Wilson                                 "WarningLow",
7653929aca1SAnthony Wilson                                 "/LowerThresholdNonCritical"_json_pointer);
76608777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
7673929aca1SAnthony Wilson                                 "CriticalHigh",
7683929aca1SAnthony Wilson                                 "/UpperThresholdCritical"_json_pointer);
76908777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
7703929aca1SAnthony Wilson                                 "CriticalLow",
7713929aca1SAnthony Wilson                                 "/LowerThresholdCritical"_json_pointer);
772de629b6eSShawn McCarney     }
77308777fb0SLewanczyk, Dawid 
7742474adfaSEd Tanous     // TODO Need to get UpperThresholdFatal and LowerThresholdFatal
7752474adfaSEd Tanous 
77695a3ecadSAnthony Wilson     if (sensorSchema == "Sensors")
77795a3ecadSAnthony Wilson     {
77895a3ecadSAnthony Wilson         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
7793929aca1SAnthony Wilson                                 "/ReadingRangeMin"_json_pointer);
78095a3ecadSAnthony Wilson         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
7813929aca1SAnthony Wilson                                 "/ReadingRangeMax"_json_pointer);
78295a3ecadSAnthony Wilson     }
78395a3ecadSAnthony Wilson     else if (sensorType == "temperature")
7841abe55efSEd Tanous     {
78508777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
7863929aca1SAnthony Wilson                                 "/MinReadingRangeTemp"_json_pointer);
78708777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
7883929aca1SAnthony Wilson                                 "/MaxReadingRangeTemp"_json_pointer);
7891abe55efSEd Tanous     }
790adc4f0dbSShawn McCarney     else if (sensorType != "power")
7911abe55efSEd Tanous     {
79208777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
7933929aca1SAnthony Wilson                                 "/MinReadingRange"_json_pointer);
79408777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
7953929aca1SAnthony Wilson                                 "/MaxReadingRange"_json_pointer);
79608777fb0SLewanczyk, Dawid     }
79708777fb0SLewanczyk, Dawid 
7983929aca1SAnthony Wilson     for (const std::tuple<const char*, const char*,
7993929aca1SAnthony Wilson                           nlohmann::json::json_pointer>& p : properties)
8001abe55efSEd Tanous     {
80108777fb0SLewanczyk, Dawid         auto interfaceProperties = interfacesDict.find(std::get<0>(p));
8021abe55efSEd Tanous         if (interfaceProperties != interfacesDict.end())
8031abe55efSEd Tanous         {
804271584abSEd Tanous             auto thisValueIt = interfaceProperties->second.find(std::get<1>(p));
805271584abSEd Tanous             if (thisValueIt != interfaceProperties->second.end())
8061abe55efSEd Tanous             {
807271584abSEd Tanous                 const SensorVariant& valueVariant = thisValueIt->second;
8083929aca1SAnthony Wilson 
8093929aca1SAnthony Wilson                 // The property we want to set may be nested json, so use
8103929aca1SAnthony Wilson                 // a json_pointer for easy indexing into the json structure.
8113929aca1SAnthony Wilson                 const nlohmann::json::json_pointer& key = std::get<2>(p);
8123929aca1SAnthony Wilson 
81308777fb0SLewanczyk, Dawid                 // Attempt to pull the int64 directly
814abf2add6SEd Tanous                 const int64_t* int64Value = std::get_if<int64_t>(&valueVariant);
81508777fb0SLewanczyk, Dawid 
816abf2add6SEd Tanous                 const double* doubleValue = std::get_if<double>(&valueVariant);
817028f7ebcSEddie James                 const uint32_t* uValue = std::get_if<uint32_t>(&valueVariant);
8186f6d0d32SEd Tanous                 double temp = 0.0;
8196f6d0d32SEd Tanous                 if (int64Value != nullptr)
8201abe55efSEd Tanous                 {
821271584abSEd Tanous                     temp = static_cast<double>(*int64Value);
8226f6d0d32SEd Tanous                 }
8236f6d0d32SEd Tanous                 else if (doubleValue != nullptr)
8241abe55efSEd Tanous                 {
8256f6d0d32SEd Tanous                     temp = *doubleValue;
8261abe55efSEd Tanous                 }
827028f7ebcSEddie James                 else if (uValue != nullptr)
828028f7ebcSEddie James                 {
829028f7ebcSEddie James                     temp = *uValue;
830028f7ebcSEddie James                 }
8311abe55efSEd Tanous                 else
8321abe55efSEd Tanous                 {
8336f6d0d32SEd Tanous                     BMCWEB_LOG_ERROR
8346f6d0d32SEd Tanous                         << "Got value interface that wasn't int or double";
8356f6d0d32SEd Tanous                     continue;
83608777fb0SLewanczyk, Dawid                 }
8376f6d0d32SEd Tanous                 temp = temp * std::pow(10, scaleMultiplier);
8386f6d0d32SEd Tanous                 if (forceToInt)
8396f6d0d32SEd Tanous                 {
8403929aca1SAnthony Wilson                     sensor_json[key] = static_cast<int64_t>(temp);
8416f6d0d32SEd Tanous                 }
8426f6d0d32SEd Tanous                 else
8436f6d0d32SEd Tanous                 {
8443929aca1SAnthony Wilson                     sensor_json[key] = temp;
84508777fb0SLewanczyk, Dawid                 }
84608777fb0SLewanczyk, Dawid             }
84708777fb0SLewanczyk, Dawid         }
84808777fb0SLewanczyk, Dawid     }
84955c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
85008777fb0SLewanczyk, Dawid }
85108777fb0SLewanczyk, Dawid 
8528bd25ccdSJames Feist static void
8538bd25ccdSJames Feist     populateFanRedundancy(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp)
8548bd25ccdSJames Feist {
8558bd25ccdSJames Feist     crow::connections::systemBus->async_method_call(
8568bd25ccdSJames Feist         [sensorsAsyncResp](const boost::system::error_code ec,
8578bd25ccdSJames Feist                            const GetSubTreeType& resp) {
8588bd25ccdSJames Feist             if (ec)
8598bd25ccdSJames Feist             {
8608bd25ccdSJames Feist                 return; // don't have to have this interface
8618bd25ccdSJames Feist             }
862e278c18fSEd Tanous             for (const std::pair<std::string,
863e278c18fSEd Tanous                                  std::vector<std::pair<
864e278c18fSEd Tanous                                      std::string, std::vector<std::string>>>>&
865e278c18fSEd Tanous                      pathPair : resp)
8668bd25ccdSJames Feist             {
867e278c18fSEd Tanous                 const std::string& path = pathPair.first;
868e278c18fSEd Tanous                 const std::vector<
869e278c18fSEd Tanous                     std::pair<std::string, std::vector<std::string>>>& objDict =
870e278c18fSEd Tanous                     pathPair.second;
8718bd25ccdSJames Feist                 if (objDict.empty())
8728bd25ccdSJames Feist                 {
8738bd25ccdSJames Feist                     continue; // this should be impossible
8748bd25ccdSJames Feist                 }
8758bd25ccdSJames Feist 
8768bd25ccdSJames Feist                 const std::string& owner = objDict.begin()->first;
8778bd25ccdSJames Feist                 crow::connections::systemBus->async_method_call(
8788bd25ccdSJames Feist                     [path, owner,
879271584abSEd Tanous                      sensorsAsyncResp](const boost::system::error_code e,
8808bd25ccdSJames Feist                                        std::variant<std::vector<std::string>>
8818bd25ccdSJames Feist                                            variantEndpoints) {
882271584abSEd Tanous                         if (e)
8838bd25ccdSJames Feist                         {
8848bd25ccdSJames Feist                             return; // if they don't have an association we
8858bd25ccdSJames Feist                                     // can't tell what chassis is
8868bd25ccdSJames Feist                         }
8878bd25ccdSJames Feist                         // verify part of the right chassis
8888bd25ccdSJames Feist                         auto endpoints = std::get_if<std::vector<std::string>>(
8898bd25ccdSJames Feist                             &variantEndpoints);
8908bd25ccdSJames Feist 
8918bd25ccdSJames Feist                         if (endpoints == nullptr)
8928bd25ccdSJames Feist                         {
8938bd25ccdSJames Feist                             BMCWEB_LOG_ERROR << "Invalid association interface";
8948bd25ccdSJames Feist                             messages::internalError(sensorsAsyncResp->res);
8958bd25ccdSJames Feist                             return;
8968bd25ccdSJames Feist                         }
8978bd25ccdSJames Feist 
8988bd25ccdSJames Feist                         auto found = std::find_if(
8998bd25ccdSJames Feist                             endpoints->begin(), endpoints->end(),
9008bd25ccdSJames Feist                             [sensorsAsyncResp](const std::string& entry) {
9018bd25ccdSJames Feist                                 return entry.find(
9028bd25ccdSJames Feist                                            sensorsAsyncResp->chassisId) !=
9038bd25ccdSJames Feist                                        std::string::npos;
9048bd25ccdSJames Feist                             });
9058bd25ccdSJames Feist 
9068bd25ccdSJames Feist                         if (found == endpoints->end())
9078bd25ccdSJames Feist                         {
9088bd25ccdSJames Feist                             return;
9098bd25ccdSJames Feist                         }
9108bd25ccdSJames Feist                         crow::connections::systemBus->async_method_call(
9118bd25ccdSJames Feist                             [path, sensorsAsyncResp](
912271584abSEd Tanous                                 const boost::system::error_code& err,
9138bd25ccdSJames Feist                                 const boost::container::flat_map<
9148bd25ccdSJames Feist                                     std::string,
9158bd25ccdSJames Feist                                     std::variant<uint8_t,
9168bd25ccdSJames Feist                                                  std::vector<std::string>,
9178bd25ccdSJames Feist                                                  std::string>>& ret) {
918271584abSEd Tanous                                 if (err)
9198bd25ccdSJames Feist                                 {
9208bd25ccdSJames Feist                                     return; // don't have to have this
9218bd25ccdSJames Feist                                             // interface
9228bd25ccdSJames Feist                                 }
9238bd25ccdSJames Feist                                 auto findFailures = ret.find("AllowedFailures");
9248bd25ccdSJames Feist                                 auto findCollection = ret.find("Collection");
9258bd25ccdSJames Feist                                 auto findStatus = ret.find("Status");
9268bd25ccdSJames Feist 
9278bd25ccdSJames Feist                                 if (findFailures == ret.end() ||
9288bd25ccdSJames Feist                                     findCollection == ret.end() ||
9298bd25ccdSJames Feist                                     findStatus == ret.end())
9308bd25ccdSJames Feist                                 {
9318bd25ccdSJames Feist                                     BMCWEB_LOG_ERROR
9328bd25ccdSJames Feist                                         << "Invalid redundancy interface";
9338bd25ccdSJames Feist                                     messages::internalError(
9348bd25ccdSJames Feist                                         sensorsAsyncResp->res);
9358bd25ccdSJames Feist                                     return;
9368bd25ccdSJames Feist                                 }
9378bd25ccdSJames Feist 
9388bd25ccdSJames Feist                                 auto allowedFailures = std::get_if<uint8_t>(
9398bd25ccdSJames Feist                                     &(findFailures->second));
9408bd25ccdSJames Feist                                 auto collection =
9418bd25ccdSJames Feist                                     std::get_if<std::vector<std::string>>(
9428bd25ccdSJames Feist                                         &(findCollection->second));
9438bd25ccdSJames Feist                                 auto status = std::get_if<std::string>(
9448bd25ccdSJames Feist                                     &(findStatus->second));
9458bd25ccdSJames Feist 
9468bd25ccdSJames Feist                                 if (allowedFailures == nullptr ||
9478bd25ccdSJames Feist                                     collection == nullptr || status == nullptr)
9488bd25ccdSJames Feist                                 {
9498bd25ccdSJames Feist 
9508bd25ccdSJames Feist                                     BMCWEB_LOG_ERROR
9518bd25ccdSJames Feist                                         << "Invalid redundancy interface "
9528bd25ccdSJames Feist                                            "types";
9538bd25ccdSJames Feist                                     messages::internalError(
9548bd25ccdSJames Feist                                         sensorsAsyncResp->res);
9558bd25ccdSJames Feist                                     return;
9568bd25ccdSJames Feist                                 }
9578bd25ccdSJames Feist                                 size_t lastSlash = path.rfind("/");
9588bd25ccdSJames Feist                                 if (lastSlash == std::string::npos)
9598bd25ccdSJames Feist                                 {
9608bd25ccdSJames Feist                                     // this should be impossible
9618bd25ccdSJames Feist                                     messages::internalError(
9628bd25ccdSJames Feist                                         sensorsAsyncResp->res);
9638bd25ccdSJames Feist                                     return;
9648bd25ccdSJames Feist                                 }
9658bd25ccdSJames Feist                                 std::string name = path.substr(lastSlash + 1);
9668bd25ccdSJames Feist                                 std::replace(name.begin(), name.end(), '_',
9678bd25ccdSJames Feist                                              ' ');
9688bd25ccdSJames Feist 
9698bd25ccdSJames Feist                                 std::string health;
9708bd25ccdSJames Feist 
9718bd25ccdSJames Feist                                 if (boost::ends_with(*status, "Full"))
9728bd25ccdSJames Feist                                 {
9738bd25ccdSJames Feist                                     health = "OK";
9748bd25ccdSJames Feist                                 }
9758bd25ccdSJames Feist                                 else if (boost::ends_with(*status, "Degraded"))
9768bd25ccdSJames Feist                                 {
9778bd25ccdSJames Feist                                     health = "Warning";
9788bd25ccdSJames Feist                                 }
9798bd25ccdSJames Feist                                 else
9808bd25ccdSJames Feist                                 {
9818bd25ccdSJames Feist                                     health = "Critical";
9828bd25ccdSJames Feist                                 }
9838bd25ccdSJames Feist                                 std::vector<nlohmann::json> redfishCollection;
9848bd25ccdSJames Feist                                 const auto& fanRedfish =
9858bd25ccdSJames Feist                                     sensorsAsyncResp->res.jsonValue["Fans"];
9868bd25ccdSJames Feist                                 for (const std::string& item : *collection)
9878bd25ccdSJames Feist                                 {
9888bd25ccdSJames Feist                                     lastSlash = item.rfind("/");
9898bd25ccdSJames Feist                                     // make a copy as collection is const
9908bd25ccdSJames Feist                                     std::string itemName =
9918bd25ccdSJames Feist                                         item.substr(lastSlash + 1);
9928bd25ccdSJames Feist                                     /*
9938bd25ccdSJames Feist                                     todo(ed): merge patch that fixes the names
9948bd25ccdSJames Feist                                     std::replace(itemName.begin(),
9958bd25ccdSJames Feist                                                  itemName.end(), '_', ' ');*/
9968bd25ccdSJames Feist                                     auto schemaItem = std::find_if(
9978bd25ccdSJames Feist                                         fanRedfish.begin(), fanRedfish.end(),
9988bd25ccdSJames Feist                                         [itemName](const nlohmann::json& fan) {
9998bd25ccdSJames Feist                                             return fan["MemberId"] == itemName;
10008bd25ccdSJames Feist                                         });
10018bd25ccdSJames Feist                                     if (schemaItem != fanRedfish.end())
10028bd25ccdSJames Feist                                     {
10038bd25ccdSJames Feist                                         redfishCollection.push_back(
10048bd25ccdSJames Feist                                             {{"@odata.id",
10058bd25ccdSJames Feist                                               (*schemaItem)["@odata.id"]}});
10068bd25ccdSJames Feist                                     }
10078bd25ccdSJames Feist                                     else
10088bd25ccdSJames Feist                                     {
10098bd25ccdSJames Feist                                         BMCWEB_LOG_ERROR
10108bd25ccdSJames Feist                                             << "failed to find fan in schema";
10118bd25ccdSJames Feist                                         messages::internalError(
10128bd25ccdSJames Feist                                             sensorsAsyncResp->res);
10138bd25ccdSJames Feist                                         return;
10148bd25ccdSJames Feist                                     }
10158bd25ccdSJames Feist                                 }
10168bd25ccdSJames Feist 
1017271584abSEd Tanous                                 nlohmann::json& jResp =
1018271584abSEd Tanous                                     sensorsAsyncResp->res
10198bd25ccdSJames Feist                                         .jsonValue["Redundancy"];
1020271584abSEd Tanous                                 jResp.push_back(
10218bd25ccdSJames Feist                                     {{"@odata.id",
1022717794d5SAppaRao Puli                                       "/redfish/v1/Chassis/" +
10238bd25ccdSJames Feist                                           sensorsAsyncResp->chassisId + "/" +
10248bd25ccdSJames Feist                                           sensorsAsyncResp->chassisSubNode +
10258bd25ccdSJames Feist                                           "#/Redundancy/" +
1026271584abSEd Tanous                                           std::to_string(jResp.size())},
10278bd25ccdSJames Feist                                      {"@odata.type",
10288bd25ccdSJames Feist                                       "#Redundancy.v1_3_2.Redundancy"},
10298bd25ccdSJames Feist                                      {"MinNumNeeded",
10308bd25ccdSJames Feist                                       collection->size() - *allowedFailures},
10318bd25ccdSJames Feist                                      {"MemberId", name},
10328bd25ccdSJames Feist                                      {"Mode", "N+m"},
10338bd25ccdSJames Feist                                      {"Name", name},
10348bd25ccdSJames Feist                                      {"RedundancySet", redfishCollection},
10358bd25ccdSJames Feist                                      {"Status",
10368bd25ccdSJames Feist                                       {{"Health", health},
10378bd25ccdSJames Feist                                        {"State", "Enabled"}}}});
10388bd25ccdSJames Feist                             },
10398bd25ccdSJames Feist                             owner, path, "org.freedesktop.DBus.Properties",
10408bd25ccdSJames Feist                             "GetAll",
10418bd25ccdSJames Feist                             "xyz.openbmc_project.Control.FanRedundancy");
10428bd25ccdSJames Feist                     },
104302e92e32SJames Feist                     "xyz.openbmc_project.ObjectMapper", path + "/chassis",
10448bd25ccdSJames Feist                     "org.freedesktop.DBus.Properties", "Get",
10458bd25ccdSJames Feist                     "xyz.openbmc_project.Association", "endpoints");
10468bd25ccdSJames Feist             }
10478bd25ccdSJames Feist         },
10488bd25ccdSJames Feist         "xyz.openbmc_project.ObjectMapper",
10498bd25ccdSJames Feist         "/xyz/openbmc_project/object_mapper",
10508bd25ccdSJames Feist         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
10518bd25ccdSJames Feist         "/xyz/openbmc_project/control", 2,
10528bd25ccdSJames Feist         std::array<const char*, 1>{
10538bd25ccdSJames Feist             "xyz.openbmc_project.Control.FanRedundancy"});
10548bd25ccdSJames Feist }
10558bd25ccdSJames Feist 
105649c53ac9SJohnathan Mantey void sortJSONResponse(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
105749c53ac9SJohnathan Mantey {
105849c53ac9SJohnathan Mantey     nlohmann::json& response = SensorsAsyncResp->res.jsonValue;
105949c53ac9SJohnathan Mantey     std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
106049c53ac9SJohnathan Mantey     if (SensorsAsyncResp->chassisSubNode == "Power")
106149c53ac9SJohnathan Mantey     {
106249c53ac9SJohnathan Mantey         sensorHeaders = {"Voltages", "PowerSupplies"};
106349c53ac9SJohnathan Mantey     }
106449c53ac9SJohnathan Mantey     for (const std::string& sensorGroup : sensorHeaders)
106549c53ac9SJohnathan Mantey     {
106649c53ac9SJohnathan Mantey         nlohmann::json::iterator entry = response.find(sensorGroup);
106749c53ac9SJohnathan Mantey         if (entry != response.end())
106849c53ac9SJohnathan Mantey         {
106949c53ac9SJohnathan Mantey             std::sort(entry->begin(), entry->end(),
107049c53ac9SJohnathan Mantey                       [](nlohmann::json& c1, nlohmann::json& c2) {
107149c53ac9SJohnathan Mantey                           return c1["Name"] < c2["Name"];
107249c53ac9SJohnathan Mantey                       });
107349c53ac9SJohnathan Mantey 
107449c53ac9SJohnathan Mantey             // add the index counts to the end of each entry
107549c53ac9SJohnathan Mantey             size_t count = 0;
107649c53ac9SJohnathan Mantey             for (nlohmann::json& sensorJson : *entry)
107749c53ac9SJohnathan Mantey             {
107849c53ac9SJohnathan Mantey                 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
107949c53ac9SJohnathan Mantey                 if (odata == sensorJson.end())
108049c53ac9SJohnathan Mantey                 {
108149c53ac9SJohnathan Mantey                     continue;
108249c53ac9SJohnathan Mantey                 }
108349c53ac9SJohnathan Mantey                 std::string* value = odata->get_ptr<std::string*>();
108449c53ac9SJohnathan Mantey                 if (value != nullptr)
108549c53ac9SJohnathan Mantey                 {
108649c53ac9SJohnathan Mantey                     *value += std::to_string(count);
108749c53ac9SJohnathan Mantey                     count++;
108849c53ac9SJohnathan Mantey                 }
108949c53ac9SJohnathan Mantey             }
109049c53ac9SJohnathan Mantey         }
109149c53ac9SJohnathan Mantey     }
109249c53ac9SJohnathan Mantey }
109349c53ac9SJohnathan Mantey 
109408777fb0SLewanczyk, Dawid /**
1095adc4f0dbSShawn McCarney  * @brief Finds the inventory item with the specified object path.
1096adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
1097adc4f0dbSShawn McCarney  * @param invItemObjPath D-Bus object path of inventory item.
1098adc4f0dbSShawn McCarney  * @return Inventory item within vector, or nullptr if no match found.
10998fb49dd6SShawn McCarney  */
1100adc4f0dbSShawn McCarney static InventoryItem* findInventoryItem(
1101adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1102adc4f0dbSShawn McCarney     const std::string& invItemObjPath)
11038fb49dd6SShawn McCarney {
1104adc4f0dbSShawn McCarney     for (InventoryItem& inventoryItem : *inventoryItems)
11058fb49dd6SShawn McCarney     {
1106adc4f0dbSShawn McCarney         if (inventoryItem.objectPath == invItemObjPath)
11078fb49dd6SShawn McCarney         {
1108adc4f0dbSShawn McCarney             return &inventoryItem;
11098fb49dd6SShawn McCarney         }
11108fb49dd6SShawn McCarney     }
11118fb49dd6SShawn McCarney     return nullptr;
11128fb49dd6SShawn McCarney }
11138fb49dd6SShawn McCarney 
11148fb49dd6SShawn McCarney /**
1115adc4f0dbSShawn McCarney  * @brief Finds the inventory item associated with the specified sensor.
1116adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
1117adc4f0dbSShawn McCarney  * @param sensorObjPath D-Bus object path of sensor.
1118adc4f0dbSShawn McCarney  * @return Inventory item within vector, or nullptr if no match found.
11198fb49dd6SShawn McCarney  */
1120adc4f0dbSShawn McCarney static InventoryItem* findInventoryItemForSensor(
1121adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1122adc4f0dbSShawn McCarney     const std::string& sensorObjPath)
1123adc4f0dbSShawn McCarney {
1124adc4f0dbSShawn McCarney     for (InventoryItem& inventoryItem : *inventoryItems)
1125adc4f0dbSShawn McCarney     {
1126adc4f0dbSShawn McCarney         if (inventoryItem.sensors.count(sensorObjPath) > 0)
1127adc4f0dbSShawn McCarney         {
1128adc4f0dbSShawn McCarney             return &inventoryItem;
1129adc4f0dbSShawn McCarney         }
1130adc4f0dbSShawn McCarney     }
1131adc4f0dbSShawn McCarney     return nullptr;
1132adc4f0dbSShawn McCarney }
1133adc4f0dbSShawn McCarney 
1134adc4f0dbSShawn McCarney /**
1135adc4f0dbSShawn McCarney  * @brief Adds inventory item and associated sensor to specified vector.
1136adc4f0dbSShawn McCarney  *
1137adc4f0dbSShawn McCarney  * Adds a new InventoryItem to the vector if necessary.  Searches for an
1138adc4f0dbSShawn McCarney  * existing InventoryItem with the specified object path.  If not found, one is
1139adc4f0dbSShawn McCarney  * added to the vector.
1140adc4f0dbSShawn McCarney  *
1141adc4f0dbSShawn McCarney  * Next, the specified sensor is added to the set of sensors associated with the
1142adc4f0dbSShawn McCarney  * InventoryItem.
1143adc4f0dbSShawn McCarney  *
1144adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
1145adc4f0dbSShawn McCarney  * @param invItemObjPath D-Bus object path of inventory item.
1146adc4f0dbSShawn McCarney  * @param sensorObjPath D-Bus object path of sensor
1147adc4f0dbSShawn McCarney  */
1148adc4f0dbSShawn McCarney static void
1149adc4f0dbSShawn McCarney     addInventoryItem(std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1150adc4f0dbSShawn McCarney                      const std::string& invItemObjPath,
1151adc4f0dbSShawn McCarney                      const std::string& sensorObjPath)
1152adc4f0dbSShawn McCarney {
1153adc4f0dbSShawn McCarney     // Look for inventory item in vector
1154adc4f0dbSShawn McCarney     InventoryItem* inventoryItem =
1155adc4f0dbSShawn McCarney         findInventoryItem(inventoryItems, invItemObjPath);
1156adc4f0dbSShawn McCarney 
1157adc4f0dbSShawn McCarney     // If inventory item doesn't exist in vector, add it
1158adc4f0dbSShawn McCarney     if (inventoryItem == nullptr)
1159adc4f0dbSShawn McCarney     {
1160adc4f0dbSShawn McCarney         inventoryItems->emplace_back(invItemObjPath);
1161adc4f0dbSShawn McCarney         inventoryItem = &(inventoryItems->back());
1162adc4f0dbSShawn McCarney     }
1163adc4f0dbSShawn McCarney 
1164adc4f0dbSShawn McCarney     // Add sensor to set of sensors associated with inventory item
1165adc4f0dbSShawn McCarney     inventoryItem->sensors.emplace(sensorObjPath);
1166adc4f0dbSShawn McCarney }
1167adc4f0dbSShawn McCarney 
1168adc4f0dbSShawn McCarney /**
1169adc4f0dbSShawn McCarney  * @brief Stores D-Bus data in the specified inventory item.
1170adc4f0dbSShawn McCarney  *
1171adc4f0dbSShawn McCarney  * Finds D-Bus data in the specified map of interfaces.  Stores the data in the
1172adc4f0dbSShawn McCarney  * specified InventoryItem.
1173adc4f0dbSShawn McCarney  *
1174adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
1175adc4f0dbSShawn McCarney  * response.
1176adc4f0dbSShawn McCarney  *
1177adc4f0dbSShawn McCarney  * @param inventoryItem Inventory item where data will be stored.
1178adc4f0dbSShawn McCarney  * @param interfacesDict Map containing D-Bus interfaces and their properties
1179adc4f0dbSShawn McCarney  * for the specified inventory item.
1180adc4f0dbSShawn McCarney  */
1181adc4f0dbSShawn McCarney static void storeInventoryItemData(
1182adc4f0dbSShawn McCarney     InventoryItem& inventoryItem,
11838fb49dd6SShawn McCarney     const boost::container::flat_map<
11848fb49dd6SShawn McCarney         std::string, boost::container::flat_map<std::string, SensorVariant>>&
11858fb49dd6SShawn McCarney         interfacesDict)
11868fb49dd6SShawn McCarney {
1187adc4f0dbSShawn McCarney     // Get properties from Inventory.Item interface
1188adc4f0dbSShawn McCarney     auto interfaceIt =
1189adc4f0dbSShawn McCarney         interfacesDict.find("xyz.openbmc_project.Inventory.Item");
1190adc4f0dbSShawn McCarney     if (interfaceIt != interfacesDict.end())
11918fb49dd6SShawn McCarney     {
1192adc4f0dbSShawn McCarney         auto propertyIt = interfaceIt->second.find("Present");
1193adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
11948fb49dd6SShawn McCarney         {
1195adc4f0dbSShawn McCarney             const bool* value = std::get_if<bool>(&propertyIt->second);
1196adc4f0dbSShawn McCarney             if (value != nullptr)
11978fb49dd6SShawn McCarney             {
1198adc4f0dbSShawn McCarney                 inventoryItem.isPresent = *value;
11998fb49dd6SShawn McCarney             }
12008fb49dd6SShawn McCarney         }
12018fb49dd6SShawn McCarney     }
12028fb49dd6SShawn McCarney 
1203adc4f0dbSShawn McCarney     // Check if Inventory.Item.PowerSupply interface is present
1204adc4f0dbSShawn McCarney     interfaceIt =
1205adc4f0dbSShawn McCarney         interfacesDict.find("xyz.openbmc_project.Inventory.Item.PowerSupply");
1206adc4f0dbSShawn McCarney     if (interfaceIt != interfacesDict.end())
12078fb49dd6SShawn McCarney     {
1208adc4f0dbSShawn McCarney         inventoryItem.isPowerSupply = true;
12098fb49dd6SShawn McCarney     }
1210adc4f0dbSShawn McCarney 
1211adc4f0dbSShawn McCarney     // Get properties from Inventory.Decorator.Asset interface
1212adc4f0dbSShawn McCarney     interfaceIt =
1213adc4f0dbSShawn McCarney         interfacesDict.find("xyz.openbmc_project.Inventory.Decorator.Asset");
1214adc4f0dbSShawn McCarney     if (interfaceIt != interfacesDict.end())
1215adc4f0dbSShawn McCarney     {
1216adc4f0dbSShawn McCarney         auto propertyIt = interfaceIt->second.find("Manufacturer");
1217adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1218adc4f0dbSShawn McCarney         {
1219adc4f0dbSShawn McCarney             const std::string* value =
1220adc4f0dbSShawn McCarney                 std::get_if<std::string>(&propertyIt->second);
1221adc4f0dbSShawn McCarney             if (value != nullptr)
1222adc4f0dbSShawn McCarney             {
1223adc4f0dbSShawn McCarney                 inventoryItem.manufacturer = *value;
1224adc4f0dbSShawn McCarney             }
1225adc4f0dbSShawn McCarney         }
1226adc4f0dbSShawn McCarney 
1227adc4f0dbSShawn McCarney         propertyIt = interfaceIt->second.find("Model");
1228adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1229adc4f0dbSShawn McCarney         {
1230adc4f0dbSShawn McCarney             const std::string* value =
1231adc4f0dbSShawn McCarney                 std::get_if<std::string>(&propertyIt->second);
1232adc4f0dbSShawn McCarney             if (value != nullptr)
1233adc4f0dbSShawn McCarney             {
1234adc4f0dbSShawn McCarney                 inventoryItem.model = *value;
1235adc4f0dbSShawn McCarney             }
1236adc4f0dbSShawn McCarney         }
1237adc4f0dbSShawn McCarney 
1238adc4f0dbSShawn McCarney         propertyIt = interfaceIt->second.find("PartNumber");
1239adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1240adc4f0dbSShawn McCarney         {
1241adc4f0dbSShawn McCarney             const std::string* value =
1242adc4f0dbSShawn McCarney                 std::get_if<std::string>(&propertyIt->second);
1243adc4f0dbSShawn McCarney             if (value != nullptr)
1244adc4f0dbSShawn McCarney             {
1245adc4f0dbSShawn McCarney                 inventoryItem.partNumber = *value;
1246adc4f0dbSShawn McCarney             }
1247adc4f0dbSShawn McCarney         }
1248adc4f0dbSShawn McCarney 
1249adc4f0dbSShawn McCarney         propertyIt = interfaceIt->second.find("SerialNumber");
1250adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1251adc4f0dbSShawn McCarney         {
1252adc4f0dbSShawn McCarney             const std::string* value =
1253adc4f0dbSShawn McCarney                 std::get_if<std::string>(&propertyIt->second);
1254adc4f0dbSShawn McCarney             if (value != nullptr)
1255adc4f0dbSShawn McCarney             {
1256adc4f0dbSShawn McCarney                 inventoryItem.serialNumber = *value;
1257adc4f0dbSShawn McCarney             }
1258adc4f0dbSShawn McCarney         }
1259adc4f0dbSShawn McCarney     }
1260adc4f0dbSShawn McCarney 
1261adc4f0dbSShawn McCarney     // Get properties from State.Decorator.OperationalStatus interface
1262adc4f0dbSShawn McCarney     interfaceIt = interfacesDict.find(
1263adc4f0dbSShawn McCarney         "xyz.openbmc_project.State.Decorator.OperationalStatus");
1264adc4f0dbSShawn McCarney     if (interfaceIt != interfacesDict.end())
1265adc4f0dbSShawn McCarney     {
1266adc4f0dbSShawn McCarney         auto propertyIt = interfaceIt->second.find("Functional");
1267adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1268adc4f0dbSShawn McCarney         {
1269adc4f0dbSShawn McCarney             const bool* value = std::get_if<bool>(&propertyIt->second);
1270adc4f0dbSShawn McCarney             if (value != nullptr)
1271adc4f0dbSShawn McCarney             {
1272adc4f0dbSShawn McCarney                 inventoryItem.isFunctional = *value;
12738fb49dd6SShawn McCarney             }
12748fb49dd6SShawn McCarney         }
12758fb49dd6SShawn McCarney     }
12768fb49dd6SShawn McCarney }
12778fb49dd6SShawn McCarney 
12788fb49dd6SShawn McCarney /**
1279adc4f0dbSShawn McCarney  * @brief Gets D-Bus data for inventory items associated with sensors.
12808fb49dd6SShawn McCarney  *
1281adc4f0dbSShawn McCarney  * Uses the specified connections (services) to obtain D-Bus data for inventory
1282adc4f0dbSShawn McCarney  * items associated with sensors.  Stores the resulting data in the
1283adc4f0dbSShawn McCarney  * inventoryItems vector.
12848fb49dd6SShawn McCarney  *
1285adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
1286adc4f0dbSShawn McCarney  * response.
1287adc4f0dbSShawn McCarney  *
1288adc4f0dbSShawn McCarney  * Finds the inventory item data asynchronously.  Invokes callback when data has
1289adc4f0dbSShawn McCarney  * been obtained.
1290adc4f0dbSShawn McCarney  *
1291adc4f0dbSShawn McCarney  * The callback must have the following signature:
1292adc4f0dbSShawn McCarney  *   @code
1293adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1294adc4f0dbSShawn McCarney  *   @endcode
1295adc4f0dbSShawn McCarney  *
1296adc4f0dbSShawn McCarney  * This function is called recursively, obtaining data asynchronously from one
1297adc4f0dbSShawn McCarney  * connection in each call.  This ensures the callback is not invoked until the
1298adc4f0dbSShawn McCarney  * last asynchronous function has completed.
12998fb49dd6SShawn McCarney  *
13008fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
1301adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
1302adc4f0dbSShawn McCarney  * @param invConnections Connections that provide data for the inventory items.
13038fb49dd6SShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
13048fb49dd6SShawn McCarney  * implements ObjectManager.
1305adc4f0dbSShawn McCarney  * @param callback Callback to invoke when inventory data has been obtained.
1306adc4f0dbSShawn McCarney  * @param invConnectionsIndex Current index in invConnections.  Only specified
1307adc4f0dbSShawn McCarney  * in recursive calls to this function.
13088fb49dd6SShawn McCarney  */
1309adc4f0dbSShawn McCarney template <typename Callback>
1310adc4f0dbSShawn McCarney static void getInventoryItemsData(
13118fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1312adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
13138fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_set<std::string>> invConnections,
13148fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1315adc4f0dbSShawn McCarney         objectMgrPaths,
1316271584abSEd Tanous     Callback&& callback, size_t invConnectionsIndex = 0)
13178fb49dd6SShawn McCarney {
1318adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsData enter";
13198fb49dd6SShawn McCarney 
1320adc4f0dbSShawn McCarney     // If no more connections left, call callback
1321adc4f0dbSShawn McCarney     if (invConnectionsIndex >= invConnections->size())
13228fb49dd6SShawn McCarney     {
1323adc4f0dbSShawn McCarney         callback(inventoryItems);
1324adc4f0dbSShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemsData exit";
1325adc4f0dbSShawn McCarney         return;
1326adc4f0dbSShawn McCarney     }
1327adc4f0dbSShawn McCarney 
1328adc4f0dbSShawn McCarney     // Get inventory item data from current connection
1329adc4f0dbSShawn McCarney     auto it = invConnections->nth(invConnectionsIndex);
1330adc4f0dbSShawn McCarney     if (it != invConnections->end())
1331adc4f0dbSShawn McCarney     {
1332adc4f0dbSShawn McCarney         const std::string& invConnection = *it;
1333adc4f0dbSShawn McCarney 
13348fb49dd6SShawn McCarney         // Response handler for GetManagedObjects
1335adc4f0dbSShawn McCarney         auto respHandler = [sensorsAsyncResp, inventoryItems, invConnections,
1336adc4f0dbSShawn McCarney                             objectMgrPaths, callback{std::move(callback)},
1337adc4f0dbSShawn McCarney                             invConnectionsIndex](
1338adc4f0dbSShawn McCarney                                const boost::system::error_code ec,
13398fb49dd6SShawn McCarney                                ManagedObjectsVectorType& resp) {
1340adc4f0dbSShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemsData respHandler enter";
13418fb49dd6SShawn McCarney             if (ec)
13428fb49dd6SShawn McCarney             {
13438fb49dd6SShawn McCarney                 BMCWEB_LOG_ERROR
1344adc4f0dbSShawn McCarney                     << "getInventoryItemsData respHandler DBus error " << ec;
13458fb49dd6SShawn McCarney                 messages::internalError(sensorsAsyncResp->res);
13468fb49dd6SShawn McCarney                 return;
13478fb49dd6SShawn McCarney             }
13488fb49dd6SShawn McCarney 
13498fb49dd6SShawn McCarney             // Loop through returned object paths
13508fb49dd6SShawn McCarney             for (const auto& objDictEntry : resp)
13518fb49dd6SShawn McCarney             {
13528fb49dd6SShawn McCarney                 const std::string& objPath =
13538fb49dd6SShawn McCarney                     static_cast<const std::string&>(objDictEntry.first);
13548fb49dd6SShawn McCarney 
1355adc4f0dbSShawn McCarney                 // If this object path is one of the specified inventory items
1356adc4f0dbSShawn McCarney                 InventoryItem* inventoryItem =
1357adc4f0dbSShawn McCarney                     findInventoryItem(inventoryItems, objPath);
1358adc4f0dbSShawn McCarney                 if (inventoryItem != nullptr)
13598fb49dd6SShawn McCarney                 {
1360adc4f0dbSShawn McCarney                     // Store inventory data in InventoryItem
1361adc4f0dbSShawn McCarney                     storeInventoryItemData(*inventoryItem, objDictEntry.second);
13628fb49dd6SShawn McCarney                 }
13638fb49dd6SShawn McCarney             }
13648fb49dd6SShawn McCarney 
1365adc4f0dbSShawn McCarney             // Recurse to get inventory item data from next connection
1366adc4f0dbSShawn McCarney             getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1367adc4f0dbSShawn McCarney                                   invConnections, objectMgrPaths,
1368adc4f0dbSShawn McCarney                                   std::move(callback), invConnectionsIndex + 1);
1369adc4f0dbSShawn McCarney 
1370adc4f0dbSShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemsData respHandler exit";
13718fb49dd6SShawn McCarney         };
13728fb49dd6SShawn McCarney 
13738fb49dd6SShawn McCarney         // Find DBus object path that implements ObjectManager for the current
13748fb49dd6SShawn McCarney         // connection.  If no mapping found, default to "/".
13758fb49dd6SShawn McCarney         auto iter = objectMgrPaths->find(invConnection);
13768fb49dd6SShawn McCarney         const std::string& objectMgrPath =
13778fb49dd6SShawn McCarney             (iter != objectMgrPaths->end()) ? iter->second : "/";
13788fb49dd6SShawn McCarney         BMCWEB_LOG_DEBUG << "ObjectManager path for " << invConnection << " is "
13798fb49dd6SShawn McCarney                          << objectMgrPath;
13808fb49dd6SShawn McCarney 
13818fb49dd6SShawn McCarney         // Get all object paths and their interfaces for current connection
13828fb49dd6SShawn McCarney         crow::connections::systemBus->async_method_call(
13838fb49dd6SShawn McCarney             std::move(respHandler), invConnection, objectMgrPath,
13848fb49dd6SShawn McCarney             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
13858fb49dd6SShawn McCarney     }
13868fb49dd6SShawn McCarney 
1387adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsData exit";
13888fb49dd6SShawn McCarney }
13898fb49dd6SShawn McCarney 
13908fb49dd6SShawn McCarney /**
1391adc4f0dbSShawn McCarney  * @brief Gets connections that provide D-Bus data for inventory items.
13928fb49dd6SShawn McCarney  *
1393adc4f0dbSShawn McCarney  * Gets the D-Bus connections (services) that provide data for the inventory
1394adc4f0dbSShawn McCarney  * items that are associated with sensors.
13958fb49dd6SShawn McCarney  *
13968fb49dd6SShawn McCarney  * Finds the connections asynchronously.  Invokes callback when information has
13978fb49dd6SShawn McCarney  * been obtained.
13988fb49dd6SShawn McCarney  *
13998fb49dd6SShawn McCarney  * The callback must have the following signature:
14008fb49dd6SShawn McCarney  *   @code
14018fb49dd6SShawn McCarney  *   callback(std::shared_ptr<boost::container::flat_set<std::string>>
14028fb49dd6SShawn McCarney  *            invConnections)
14038fb49dd6SShawn McCarney  *   @endcode
14048fb49dd6SShawn McCarney  *
14058fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
1406adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
14078fb49dd6SShawn McCarney  * @param callback Callback to invoke when connections have been obtained.
14088fb49dd6SShawn McCarney  */
14098fb49dd6SShawn McCarney template <typename Callback>
14108fb49dd6SShawn McCarney static void getInventoryItemsConnections(
14118fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1412adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
14138fb49dd6SShawn McCarney     Callback&& callback)
14148fb49dd6SShawn McCarney {
14158fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsConnections enter";
14168fb49dd6SShawn McCarney 
14178fb49dd6SShawn McCarney     const std::string path = "/xyz/openbmc_project/inventory";
1418adc4f0dbSShawn McCarney     const std::array<std::string, 4> interfaces = {
14198fb49dd6SShawn McCarney         "xyz.openbmc_project.Inventory.Item",
1420adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Item.PowerSupply",
1421adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Decorator.Asset",
14228fb49dd6SShawn McCarney         "xyz.openbmc_project.State.Decorator.OperationalStatus"};
14238fb49dd6SShawn McCarney 
14248fb49dd6SShawn McCarney     // Response handler for parsing output from GetSubTree
14258fb49dd6SShawn McCarney     auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
1426adc4f0dbSShawn McCarney                         inventoryItems](const boost::system::error_code ec,
14278fb49dd6SShawn McCarney                                         const GetSubTreeType& subtree) {
14288fb49dd6SShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler enter";
14298fb49dd6SShawn McCarney         if (ec)
14308fb49dd6SShawn McCarney         {
14318fb49dd6SShawn McCarney             messages::internalError(sensorsAsyncResp->res);
14328fb49dd6SShawn McCarney             BMCWEB_LOG_ERROR
14338fb49dd6SShawn McCarney                 << "getInventoryItemsConnections respHandler DBus error " << ec;
14348fb49dd6SShawn McCarney             return;
14358fb49dd6SShawn McCarney         }
14368fb49dd6SShawn McCarney 
14378fb49dd6SShawn McCarney         // Make unique list of connections for desired inventory items
14388fb49dd6SShawn McCarney         std::shared_ptr<boost::container::flat_set<std::string>>
14398fb49dd6SShawn McCarney             invConnections =
14408fb49dd6SShawn McCarney                 std::make_shared<boost::container::flat_set<std::string>>();
14418fb49dd6SShawn McCarney         invConnections->reserve(8);
14428fb49dd6SShawn McCarney 
14438fb49dd6SShawn McCarney         // Loop through objects from GetSubTree
14448fb49dd6SShawn McCarney         for (const std::pair<
14458fb49dd6SShawn McCarney                  std::string,
14468fb49dd6SShawn McCarney                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
14478fb49dd6SShawn McCarney                  object : subtree)
14488fb49dd6SShawn McCarney         {
1449adc4f0dbSShawn McCarney             // Check if object path is one of the specified inventory items
14508fb49dd6SShawn McCarney             const std::string& objPath = object.first;
1451adc4f0dbSShawn McCarney             if (findInventoryItem(inventoryItems, objPath) != nullptr)
14528fb49dd6SShawn McCarney             {
14538fb49dd6SShawn McCarney                 // Store all connections to inventory item
14548fb49dd6SShawn McCarney                 for (const std::pair<std::string, std::vector<std::string>>&
14558fb49dd6SShawn McCarney                          objData : object.second)
14568fb49dd6SShawn McCarney                 {
14578fb49dd6SShawn McCarney                     const std::string& invConnection = objData.first;
14588fb49dd6SShawn McCarney                     invConnections->insert(invConnection);
14598fb49dd6SShawn McCarney                 }
14608fb49dd6SShawn McCarney             }
14618fb49dd6SShawn McCarney         }
14628fb49dd6SShawn McCarney         callback(invConnections);
14638fb49dd6SShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler exit";
14648fb49dd6SShawn McCarney     };
14658fb49dd6SShawn McCarney 
14668fb49dd6SShawn McCarney     // Make call to ObjectMapper to find all inventory items
14678fb49dd6SShawn McCarney     crow::connections::systemBus->async_method_call(
14688fb49dd6SShawn McCarney         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
14698fb49dd6SShawn McCarney         "/xyz/openbmc_project/object_mapper",
14708fb49dd6SShawn McCarney         "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 0, interfaces);
14718fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsConnections exit";
14728fb49dd6SShawn McCarney }
14738fb49dd6SShawn McCarney 
14748fb49dd6SShawn McCarney /**
1475adc4f0dbSShawn McCarney  * @brief Gets associations from sensors to inventory items.
14768fb49dd6SShawn McCarney  *
14778fb49dd6SShawn McCarney  * Looks for ObjectMapper associations from the specified sensors to related
1478adc4f0dbSShawn McCarney  * inventory items.
14798fb49dd6SShawn McCarney  *
14808fb49dd6SShawn McCarney  * Finds the inventory items asynchronously.  Invokes callback when information
14818fb49dd6SShawn McCarney  * has been obtained.
14828fb49dd6SShawn McCarney  *
14838fb49dd6SShawn McCarney  * The callback must have the following signature:
14848fb49dd6SShawn McCarney  *   @code
1485adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
14868fb49dd6SShawn McCarney  *   @endcode
14878fb49dd6SShawn McCarney  *
14888fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
14898fb49dd6SShawn McCarney  * @param sensorNames All sensors within the current chassis.
14908fb49dd6SShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
14918fb49dd6SShawn McCarney  * implements ObjectManager.
14928fb49dd6SShawn McCarney  * @param callback Callback to invoke when inventory items have been obtained.
14938fb49dd6SShawn McCarney  */
14948fb49dd6SShawn McCarney template <typename Callback>
1495adc4f0dbSShawn McCarney static void getInventoryItemAssociations(
14968fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
14978fb49dd6SShawn McCarney     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
14988fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
14998fb49dd6SShawn McCarney         objectMgrPaths,
15008fb49dd6SShawn McCarney     Callback&& callback)
15018fb49dd6SShawn McCarney {
1502adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemAssociations enter";
15038fb49dd6SShawn McCarney 
15048fb49dd6SShawn McCarney     // Response handler for GetManagedObjects
15058fb49dd6SShawn McCarney     auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
15068fb49dd6SShawn McCarney                         sensorNames](const boost::system::error_code ec,
15078fb49dd6SShawn McCarney                                      dbus::utility::ManagedObjectType& resp) {
1508adc4f0dbSShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemAssociations respHandler enter";
15098fb49dd6SShawn McCarney         if (ec)
15108fb49dd6SShawn McCarney         {
1511adc4f0dbSShawn McCarney             BMCWEB_LOG_ERROR
1512adc4f0dbSShawn McCarney                 << "getInventoryItemAssociations respHandler DBus error " << ec;
15138fb49dd6SShawn McCarney             messages::internalError(sensorsAsyncResp->res);
15148fb49dd6SShawn McCarney             return;
15158fb49dd6SShawn McCarney         }
15168fb49dd6SShawn McCarney 
1517adc4f0dbSShawn McCarney         // Create vector to hold list of inventory items
1518adc4f0dbSShawn McCarney         std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1519adc4f0dbSShawn McCarney             std::make_shared<std::vector<InventoryItem>>();
1520adc4f0dbSShawn McCarney 
15218fb49dd6SShawn McCarney         // Loop through returned object paths
15228fb49dd6SShawn McCarney         std::string sensorAssocPath;
15238fb49dd6SShawn McCarney         sensorAssocPath.reserve(128); // avoid memory allocations
15248fb49dd6SShawn McCarney         for (const auto& objDictEntry : resp)
15258fb49dd6SShawn McCarney         {
15268fb49dd6SShawn McCarney             const std::string& objPath =
15278fb49dd6SShawn McCarney                 static_cast<const std::string&>(objDictEntry.first);
15288fb49dd6SShawn McCarney             const boost::container::flat_map<
15298fb49dd6SShawn McCarney                 std::string, boost::container::flat_map<
15308fb49dd6SShawn McCarney                                  std::string, dbus::utility::DbusVariantType>>&
15318fb49dd6SShawn McCarney                 interfacesDict = objDictEntry.second;
15328fb49dd6SShawn McCarney 
15338fb49dd6SShawn McCarney             // If path is inventory association for one of the specified sensors
15348fb49dd6SShawn McCarney             for (const std::string& sensorName : *sensorNames)
15358fb49dd6SShawn McCarney             {
15368fb49dd6SShawn McCarney                 sensorAssocPath = sensorName;
15378fb49dd6SShawn McCarney                 sensorAssocPath += "/inventory";
15388fb49dd6SShawn McCarney                 if (objPath == sensorAssocPath)
15398fb49dd6SShawn McCarney                 {
15408fb49dd6SShawn McCarney                     // Get Association interface for object path
15418fb49dd6SShawn McCarney                     auto assocIt =
15428fb49dd6SShawn McCarney                         interfacesDict.find("xyz.openbmc_project.Association");
15438fb49dd6SShawn McCarney                     if (assocIt != interfacesDict.end())
15448fb49dd6SShawn McCarney                     {
15458fb49dd6SShawn McCarney                         // Get inventory item from end point
15468fb49dd6SShawn McCarney                         auto endpointsIt = assocIt->second.find("endpoints");
15478fb49dd6SShawn McCarney                         if (endpointsIt != assocIt->second.end())
15488fb49dd6SShawn McCarney                         {
15498fb49dd6SShawn McCarney                             const std::vector<std::string>* endpoints =
15508fb49dd6SShawn McCarney                                 std::get_if<std::vector<std::string>>(
15518fb49dd6SShawn McCarney                                     &endpointsIt->second);
15528fb49dd6SShawn McCarney                             if ((endpoints != nullptr) && !endpoints->empty())
15538fb49dd6SShawn McCarney                             {
1554adc4f0dbSShawn McCarney                                 // Add inventory item to vector
1555adc4f0dbSShawn McCarney                                 const std::string& invItemPath =
1556adc4f0dbSShawn McCarney                                     endpoints->front();
1557adc4f0dbSShawn McCarney                                 addInventoryItem(inventoryItems, invItemPath,
1558adc4f0dbSShawn McCarney                                                  sensorName);
15598fb49dd6SShawn McCarney                             }
15608fb49dd6SShawn McCarney                         }
15618fb49dd6SShawn McCarney                     }
15628fb49dd6SShawn McCarney                     break;
15638fb49dd6SShawn McCarney                 }
15648fb49dd6SShawn McCarney             }
15658fb49dd6SShawn McCarney         }
15668fb49dd6SShawn McCarney 
1567adc4f0dbSShawn McCarney         callback(inventoryItems);
1568adc4f0dbSShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemAssociations respHandler exit";
15698fb49dd6SShawn McCarney     };
15708fb49dd6SShawn McCarney 
15718fb49dd6SShawn McCarney     // Find DBus object path that implements ObjectManager for ObjectMapper
15728fb49dd6SShawn McCarney     std::string connection = "xyz.openbmc_project.ObjectMapper";
15738fb49dd6SShawn McCarney     auto iter = objectMgrPaths->find(connection);
15748fb49dd6SShawn McCarney     const std::string& objectMgrPath =
15758fb49dd6SShawn McCarney         (iter != objectMgrPaths->end()) ? iter->second : "/";
15768fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
15778fb49dd6SShawn McCarney                      << objectMgrPath;
15788fb49dd6SShawn McCarney 
15798fb49dd6SShawn McCarney     // Call GetManagedObjects on the ObjectMapper to get all associations
15808fb49dd6SShawn McCarney     crow::connections::systemBus->async_method_call(
15818fb49dd6SShawn McCarney         std::move(respHandler), connection, objectMgrPath,
15828fb49dd6SShawn McCarney         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
15838fb49dd6SShawn McCarney 
1584adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemAssociations exit";
15858fb49dd6SShawn McCarney }
15868fb49dd6SShawn McCarney 
15878fb49dd6SShawn McCarney /**
1588adc4f0dbSShawn McCarney  * @brief Gets inventory items associated with sensors.
15898fb49dd6SShawn McCarney  *
15908fb49dd6SShawn McCarney  * Finds the inventory items that are associated with the specified sensors.
1591adc4f0dbSShawn McCarney  * Then gets D-Bus data for the inventory items, such as presence and VPD.
15928fb49dd6SShawn McCarney  *
1593adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
1594adc4f0dbSShawn McCarney  * response.
15958fb49dd6SShawn McCarney  *
1596adc4f0dbSShawn McCarney  * Finds the inventory items asynchronously.  Invokes callback when the
1597adc4f0dbSShawn McCarney  * inventory items have been obtained.
1598adc4f0dbSShawn McCarney  *
1599adc4f0dbSShawn McCarney  * The callback must have the following signature:
1600adc4f0dbSShawn McCarney  *   @code
1601adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1602adc4f0dbSShawn McCarney  *   @endcode
16038fb49dd6SShawn McCarney  *
16048fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
16058fb49dd6SShawn McCarney  * @param sensorNames All sensors within the current chassis.
16068fb49dd6SShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
16078fb49dd6SShawn McCarney  * implements ObjectManager.
1608adc4f0dbSShawn McCarney  * @param callback Callback to invoke when inventory items have been obtained.
16098fb49dd6SShawn McCarney  */
1610adc4f0dbSShawn McCarney template <typename Callback>
1611adc4f0dbSShawn McCarney static void getInventoryItems(
16128fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
16138fb49dd6SShawn McCarney     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
16148fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1615adc4f0dbSShawn McCarney         objectMgrPaths,
1616adc4f0dbSShawn McCarney     Callback&& callback)
16178fb49dd6SShawn McCarney {
1618adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItems enter";
1619adc4f0dbSShawn McCarney     auto getInventoryItemAssociationsCb =
1620adc4f0dbSShawn McCarney         [sensorsAsyncResp, objectMgrPaths, callback{std::move(callback)}](
1621adc4f0dbSShawn McCarney             std::shared_ptr<std::vector<InventoryItem>> inventoryItems) {
1622adc4f0dbSShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemAssociationsCb enter";
16238fb49dd6SShawn McCarney             auto getInventoryItemsConnectionsCb =
1624adc4f0dbSShawn McCarney                 [sensorsAsyncResp, inventoryItems, objectMgrPaths,
1625adc4f0dbSShawn McCarney                  callback{std::move(callback)}](
16268fb49dd6SShawn McCarney                     std::shared_ptr<boost::container::flat_set<std::string>>
16278fb49dd6SShawn McCarney                         invConnections) {
16288fb49dd6SShawn McCarney                     BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb enter";
16298fb49dd6SShawn McCarney 
1630adc4f0dbSShawn McCarney                     // Get inventory item data from connections
1631adc4f0dbSShawn McCarney                     getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1632adc4f0dbSShawn McCarney                                           invConnections, objectMgrPaths,
1633adc4f0dbSShawn McCarney                                           std::move(callback));
16348fb49dd6SShawn McCarney 
16358fb49dd6SShawn McCarney                     BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb exit";
16368fb49dd6SShawn McCarney                 };
16378fb49dd6SShawn McCarney 
1638adc4f0dbSShawn McCarney             // Get connections that provide inventory item data
16398fb49dd6SShawn McCarney             getInventoryItemsConnections(
1640adc4f0dbSShawn McCarney                 sensorsAsyncResp, inventoryItems,
16418fb49dd6SShawn McCarney                 std::move(getInventoryItemsConnectionsCb));
1642adc4f0dbSShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemAssociationsCb exit";
16438fb49dd6SShawn McCarney         };
16448fb49dd6SShawn McCarney 
1645adc4f0dbSShawn McCarney     // Get associations from sensors to inventory items
1646adc4f0dbSShawn McCarney     getInventoryItemAssociations(sensorsAsyncResp, sensorNames, objectMgrPaths,
1647adc4f0dbSShawn McCarney                                  std::move(getInventoryItemAssociationsCb));
1648adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItems exit";
1649adc4f0dbSShawn McCarney }
1650adc4f0dbSShawn McCarney 
1651adc4f0dbSShawn McCarney /**
1652adc4f0dbSShawn McCarney  * @brief Returns JSON PowerSupply object for the specified inventory item.
1653adc4f0dbSShawn McCarney  *
1654adc4f0dbSShawn McCarney  * Searches for a JSON PowerSupply object that matches the specified inventory
1655adc4f0dbSShawn McCarney  * item.  If one is not found, a new PowerSupply object is added to the JSON
1656adc4f0dbSShawn McCarney  * array.
1657adc4f0dbSShawn McCarney  *
1658adc4f0dbSShawn McCarney  * Multiple sensors are often associated with one power supply inventory item.
1659adc4f0dbSShawn McCarney  * As a result, multiple sensor values are stored in one JSON PowerSupply
1660adc4f0dbSShawn McCarney  * object.
1661adc4f0dbSShawn McCarney  *
1662adc4f0dbSShawn McCarney  * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1663adc4f0dbSShawn McCarney  * @param inventoryItem Inventory item for the power supply.
1664adc4f0dbSShawn McCarney  * @param chassisId Chassis that contains the power supply.
1665adc4f0dbSShawn McCarney  * @return JSON PowerSupply object for the specified inventory item.
1666adc4f0dbSShawn McCarney  */
1667adc4f0dbSShawn McCarney static nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
1668adc4f0dbSShawn McCarney                                       const InventoryItem& inventoryItem,
1669adc4f0dbSShawn McCarney                                       const std::string& chassisId)
1670adc4f0dbSShawn McCarney {
1671adc4f0dbSShawn McCarney     // Check if matching PowerSupply object already exists in JSON array
1672adc4f0dbSShawn McCarney     for (nlohmann::json& powerSupply : powerSupplyArray)
1673adc4f0dbSShawn McCarney     {
1674adc4f0dbSShawn McCarney         if (powerSupply["MemberId"] == inventoryItem.name)
1675adc4f0dbSShawn McCarney         {
1676adc4f0dbSShawn McCarney             return powerSupply;
1677adc4f0dbSShawn McCarney         }
1678adc4f0dbSShawn McCarney     }
1679adc4f0dbSShawn McCarney 
1680adc4f0dbSShawn McCarney     // Add new PowerSupply object to JSON array
1681adc4f0dbSShawn McCarney     powerSupplyArray.push_back({});
1682adc4f0dbSShawn McCarney     nlohmann::json& powerSupply = powerSupplyArray.back();
1683adc4f0dbSShawn McCarney     powerSupply["@odata.id"] =
1684adc4f0dbSShawn McCarney         "/redfish/v1/Chassis/" + chassisId + "/Power#/PowerSupplies/";
1685adc4f0dbSShawn McCarney     powerSupply["MemberId"] = inventoryItem.name;
1686adc4f0dbSShawn McCarney     powerSupply["Name"] = boost::replace_all_copy(inventoryItem.name, "_", " ");
1687adc4f0dbSShawn McCarney     powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1688adc4f0dbSShawn McCarney     powerSupply["Model"] = inventoryItem.model;
1689adc4f0dbSShawn McCarney     powerSupply["PartNumber"] = inventoryItem.partNumber;
1690adc4f0dbSShawn McCarney     powerSupply["SerialNumber"] = inventoryItem.serialNumber;
1691adc4f0dbSShawn McCarney     powerSupply["Status"]["State"] = getState(&inventoryItem);
1692adc4f0dbSShawn McCarney 
1693adc4f0dbSShawn McCarney     const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1694adc4f0dbSShawn McCarney     powerSupply["Status"]["Health"] = health;
1695adc4f0dbSShawn McCarney 
1696adc4f0dbSShawn McCarney     return powerSupply;
16978fb49dd6SShawn McCarney }
16988fb49dd6SShawn McCarney 
16998fb49dd6SShawn McCarney /**
1700de629b6eSShawn McCarney  * @brief Gets the values of the specified sensors.
1701de629b6eSShawn McCarney  *
1702de629b6eSShawn McCarney  * Stores the results as JSON in the SensorsAsyncResp.
1703de629b6eSShawn McCarney  *
1704de629b6eSShawn McCarney  * Gets the sensor values asynchronously.  Stores the results later when the
1705de629b6eSShawn McCarney  * information has been obtained.
1706de629b6eSShawn McCarney  *
1707adc4f0dbSShawn McCarney  * The sensorNames set contains all requested sensors for the current chassis.
1708de629b6eSShawn McCarney  *
1709de629b6eSShawn McCarney  * To minimize the number of DBus calls, the DBus method
1710de629b6eSShawn McCarney  * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1711de629b6eSShawn McCarney  * values of all sensors provided by a connection (service).
1712de629b6eSShawn McCarney  *
1713de629b6eSShawn McCarney  * The connections set contains all the connections that provide sensor values.
1714de629b6eSShawn McCarney  *
1715de629b6eSShawn McCarney  * The objectMgrPaths map contains mappings from a connection name to the
1716de629b6eSShawn McCarney  * corresponding DBus object path that implements ObjectManager.
1717de629b6eSShawn McCarney  *
1718adc4f0dbSShawn McCarney  * The InventoryItem vector contains D-Bus inventory items associated with the
1719adc4f0dbSShawn McCarney  * sensors.  Inventory item data is needed for some Redfish sensor properties.
1720adc4f0dbSShawn McCarney  *
1721de629b6eSShawn McCarney  * @param SensorsAsyncResp Pointer to object holding response data.
1722adc4f0dbSShawn McCarney  * @param sensorNames All requested sensors within the current chassis.
1723de629b6eSShawn McCarney  * @param connections Connections that provide sensor values.
1724de629b6eSShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
1725de629b6eSShawn McCarney  * implements ObjectManager.
1726adc4f0dbSShawn McCarney  * @param inventoryItems Inventory items associated with the sensors.
1727de629b6eSShawn McCarney  */
1728de629b6eSShawn McCarney void getSensorData(
1729de629b6eSShawn McCarney     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
173049c53ac9SJohnathan Mantey     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
1731de629b6eSShawn McCarney     const boost::container::flat_set<std::string>& connections,
17328fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1733adc4f0dbSShawn McCarney         objectMgrPaths,
1734adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1735de629b6eSShawn McCarney {
1736de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getSensorData enter";
1737de629b6eSShawn McCarney     // Get managed objects from all services exposing sensors
1738de629b6eSShawn McCarney     for (const std::string& connection : connections)
1739de629b6eSShawn McCarney     {
1740de629b6eSShawn McCarney         // Response handler to process managed objects
17418fb49dd6SShawn McCarney         auto getManagedObjectsCb = [SensorsAsyncResp, sensorNames,
1742adc4f0dbSShawn McCarney                                     inventoryItems](
1743de629b6eSShawn McCarney                                        const boost::system::error_code ec,
1744de629b6eSShawn McCarney                                        ManagedObjectsVectorType& resp) {
1745de629b6eSShawn McCarney             BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
1746de629b6eSShawn McCarney             if (ec)
1747de629b6eSShawn McCarney             {
1748de629b6eSShawn McCarney                 BMCWEB_LOG_ERROR << "getManagedObjectsCb DBUS error: " << ec;
1749de629b6eSShawn McCarney                 messages::internalError(SensorsAsyncResp->res);
1750de629b6eSShawn McCarney                 return;
1751de629b6eSShawn McCarney             }
1752de629b6eSShawn McCarney             // Go through all objects and update response with sensor data
1753de629b6eSShawn McCarney             for (const auto& objDictEntry : resp)
1754de629b6eSShawn McCarney             {
1755de629b6eSShawn McCarney                 const std::string& objPath =
1756de629b6eSShawn McCarney                     static_cast<const std::string&>(objDictEntry.first);
1757de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "getManagedObjectsCb parsing object "
1758de629b6eSShawn McCarney                                  << objPath;
1759de629b6eSShawn McCarney 
1760de629b6eSShawn McCarney                 std::vector<std::string> split;
1761de629b6eSShawn McCarney                 // Reserve space for
1762de629b6eSShawn McCarney                 // /xyz/openbmc_project/sensors/<name>/<subname>
1763de629b6eSShawn McCarney                 split.reserve(6);
1764de629b6eSShawn McCarney                 boost::algorithm::split(split, objPath, boost::is_any_of("/"));
1765de629b6eSShawn McCarney                 if (split.size() < 6)
1766de629b6eSShawn McCarney                 {
1767de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << "Got path that isn't long enough "
1768de629b6eSShawn McCarney                                      << objPath;
1769de629b6eSShawn McCarney                     continue;
1770de629b6eSShawn McCarney                 }
1771de629b6eSShawn McCarney                 // These indexes aren't intuitive, as boost::split puts an empty
1772de629b6eSShawn McCarney                 // string at the beginning
1773de629b6eSShawn McCarney                 const std::string& sensorType = split[4];
1774de629b6eSShawn McCarney                 const std::string& sensorName = split[5];
1775de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "sensorName " << sensorName
1776de629b6eSShawn McCarney                                  << " sensorType " << sensorType;
177749c53ac9SJohnathan Mantey                 if (sensorNames->find(objPath) == sensorNames->end())
1778de629b6eSShawn McCarney                 {
1779de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << sensorName << " not in sensor list ";
1780de629b6eSShawn McCarney                     continue;
1781de629b6eSShawn McCarney                 }
1782de629b6eSShawn McCarney 
1783adc4f0dbSShawn McCarney                 // Find inventory item (if any) associated with sensor
1784adc4f0dbSShawn McCarney                 InventoryItem* inventoryItem =
1785adc4f0dbSShawn McCarney                     findInventoryItemForSensor(inventoryItems, objPath);
1786adc4f0dbSShawn McCarney 
178795a3ecadSAnthony Wilson                 const std::string& sensorSchema =
178895a3ecadSAnthony Wilson                     SensorsAsyncResp->chassisSubNode;
178995a3ecadSAnthony Wilson 
179095a3ecadSAnthony Wilson                 nlohmann::json* sensorJson = nullptr;
179195a3ecadSAnthony Wilson 
179295a3ecadSAnthony Wilson                 if (sensorSchema == "Sensors")
179395a3ecadSAnthony Wilson                 {
179495a3ecadSAnthony Wilson                     SensorsAsyncResp->res.jsonValue["@odata.id"] =
179595a3ecadSAnthony Wilson                         "/redfish/v1/Chassis/" + SensorsAsyncResp->chassisId +
179695a3ecadSAnthony Wilson                         "/" + SensorsAsyncResp->chassisSubNode + "/" +
179795a3ecadSAnthony Wilson                         sensorName;
179895a3ecadSAnthony Wilson                     sensorJson = &(SensorsAsyncResp->res.jsonValue);
179995a3ecadSAnthony Wilson                 }
180095a3ecadSAnthony Wilson                 else
180195a3ecadSAnthony Wilson                 {
1802271584abSEd Tanous                     std::string fieldName;
1803de629b6eSShawn McCarney                     if (sensorType == "temperature")
1804de629b6eSShawn McCarney                     {
1805de629b6eSShawn McCarney                         fieldName = "Temperatures";
1806de629b6eSShawn McCarney                     }
1807de629b6eSShawn McCarney                     else if (sensorType == "fan" || sensorType == "fan_tach" ||
1808de629b6eSShawn McCarney                              sensorType == "fan_pwm")
1809de629b6eSShawn McCarney                     {
1810de629b6eSShawn McCarney                         fieldName = "Fans";
1811de629b6eSShawn McCarney                     }
1812de629b6eSShawn McCarney                     else if (sensorType == "voltage")
1813de629b6eSShawn McCarney                     {
1814de629b6eSShawn McCarney                         fieldName = "Voltages";
1815de629b6eSShawn McCarney                     }
1816de629b6eSShawn McCarney                     else if (sensorType == "power")
1817de629b6eSShawn McCarney                     {
1818028f7ebcSEddie James                         if (!sensorName.compare("total_power"))
1819028f7ebcSEddie James                         {
1820028f7ebcSEddie James                             fieldName = "PowerControl";
1821028f7ebcSEddie James                         }
1822adc4f0dbSShawn McCarney                         else if ((inventoryItem != nullptr) &&
1823adc4f0dbSShawn McCarney                                  (inventoryItem->isPowerSupply))
1824028f7ebcSEddie James                         {
1825de629b6eSShawn McCarney                             fieldName = "PowerSupplies";
1826de629b6eSShawn McCarney                         }
1827adc4f0dbSShawn McCarney                         else
1828adc4f0dbSShawn McCarney                         {
1829adc4f0dbSShawn McCarney                             // Other power sensors are in SensorCollection
1830adc4f0dbSShawn McCarney                             continue;
1831adc4f0dbSShawn McCarney                         }
1832028f7ebcSEddie James                     }
1833de629b6eSShawn McCarney                     else
1834de629b6eSShawn McCarney                     {
1835de629b6eSShawn McCarney                         BMCWEB_LOG_ERROR << "Unsure how to handle sensorType "
1836de629b6eSShawn McCarney                                          << sensorType;
1837de629b6eSShawn McCarney                         continue;
1838de629b6eSShawn McCarney                     }
1839de629b6eSShawn McCarney 
1840de629b6eSShawn McCarney                     nlohmann::json& tempArray =
1841de629b6eSShawn McCarney                         SensorsAsyncResp->res.jsonValue[fieldName];
1842adc4f0dbSShawn McCarney                     if (fieldName == "PowerControl")
184349c53ac9SJohnathan Mantey                     {
1844adc4f0dbSShawn McCarney                         if (tempArray.empty())
18457ab06f49SGunnar Mills                         {
184695a3ecadSAnthony Wilson                             // Put multiple "sensors" into a single
184795a3ecadSAnthony Wilson                             // PowerControl. Follows MemberId naming and
184895a3ecadSAnthony Wilson                             // naming in power.hpp.
18497ab06f49SGunnar Mills                             tempArray.push_back(
1850adc4f0dbSShawn McCarney                                 {{"@odata.id",
1851adc4f0dbSShawn McCarney                                   "/redfish/v1/Chassis/" +
18527ab06f49SGunnar Mills                                       SensorsAsyncResp->chassisId + "/" +
1853adc4f0dbSShawn McCarney                                       SensorsAsyncResp->chassisSubNode + "#/" +
1854adc4f0dbSShawn McCarney                                       fieldName + "/0"}});
1855adc4f0dbSShawn McCarney                         }
1856adc4f0dbSShawn McCarney                         sensorJson = &(tempArray.back());
1857adc4f0dbSShawn McCarney                     }
1858adc4f0dbSShawn McCarney                     else if (fieldName == "PowerSupplies")
1859adc4f0dbSShawn McCarney                     {
1860adc4f0dbSShawn McCarney                         if (inventoryItem != nullptr)
1861adc4f0dbSShawn McCarney                         {
1862adc4f0dbSShawn McCarney                             sensorJson =
1863adc4f0dbSShawn McCarney                                 &(getPowerSupply(tempArray, *inventoryItem,
1864adc4f0dbSShawn McCarney                                                  SensorsAsyncResp->chassisId));
1865adc4f0dbSShawn McCarney                         }
186649c53ac9SJohnathan Mantey                     }
186749c53ac9SJohnathan Mantey                     else
186849c53ac9SJohnathan Mantey                     {
1869de629b6eSShawn McCarney                         tempArray.push_back(
187095a3ecadSAnthony Wilson                             {{"@odata.id",
187195a3ecadSAnthony Wilson                               "/redfish/v1/Chassis/" +
187249c53ac9SJohnathan Mantey                                   SensorsAsyncResp->chassisId + "/" +
187395a3ecadSAnthony Wilson                                   SensorsAsyncResp->chassisSubNode + "#/" +
187495a3ecadSAnthony Wilson                                   fieldName + "/"}});
1875adc4f0dbSShawn McCarney                         sensorJson = &(tempArray.back());
187649c53ac9SJohnathan Mantey                     }
187795a3ecadSAnthony Wilson                 }
1878de629b6eSShawn McCarney 
1879adc4f0dbSShawn McCarney                 if (sensorJson != nullptr)
1880adc4f0dbSShawn McCarney                 {
1881de629b6eSShawn McCarney                     objectInterfacesToJson(sensorName, sensorType,
188295a3ecadSAnthony Wilson                                            SensorsAsyncResp->chassisSubNode,
1883adc4f0dbSShawn McCarney                                            objDictEntry.second, *sensorJson,
1884adc4f0dbSShawn McCarney                                            inventoryItem);
1885adc4f0dbSShawn McCarney                 }
1886de629b6eSShawn McCarney             }
188749c53ac9SJohnathan Mantey             if (SensorsAsyncResp.use_count() == 1)
188849c53ac9SJohnathan Mantey             {
188949c53ac9SJohnathan Mantey                 sortJSONResponse(SensorsAsyncResp);
189049c53ac9SJohnathan Mantey                 if (SensorsAsyncResp->chassisSubNode == "Thermal")
18918bd25ccdSJames Feist                 {
18928bd25ccdSJames Feist                     populateFanRedundancy(SensorsAsyncResp);
18938bd25ccdSJames Feist                 }
189449c53ac9SJohnathan Mantey             }
1895de629b6eSShawn McCarney             BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
1896de629b6eSShawn McCarney         };
1897de629b6eSShawn McCarney 
1898de629b6eSShawn McCarney         // Find DBus object path that implements ObjectManager for the current
1899de629b6eSShawn McCarney         // connection.  If no mapping found, default to "/".
19008fb49dd6SShawn McCarney         auto iter = objectMgrPaths->find(connection);
1901de629b6eSShawn McCarney         const std::string& objectMgrPath =
19028fb49dd6SShawn McCarney             (iter != objectMgrPaths->end()) ? iter->second : "/";
1903de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
1904de629b6eSShawn McCarney                          << objectMgrPath;
1905de629b6eSShawn McCarney 
1906de629b6eSShawn McCarney         crow::connections::systemBus->async_method_call(
1907de629b6eSShawn McCarney             getManagedObjectsCb, connection, objectMgrPath,
1908de629b6eSShawn McCarney             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1909de629b6eSShawn McCarney     };
1910de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getSensorData exit";
1911de629b6eSShawn McCarney }
1912de629b6eSShawn McCarney 
191395a3ecadSAnthony Wilson void processSensorList(
191495a3ecadSAnthony Wilson     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
191595a3ecadSAnthony Wilson     std::shared_ptr<boost::container::flat_set<std::string>> sensorNames)
19161abe55efSEd Tanous {
191795a3ecadSAnthony Wilson     auto getConnectionCb =
191895a3ecadSAnthony Wilson         [SensorsAsyncResp, sensorNames](
191995a3ecadSAnthony Wilson             const boost::container::flat_set<std::string>& connections) {
192055c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "getConnectionCb enter";
1921de629b6eSShawn McCarney             auto getObjectManagerPathsCb =
192249c53ac9SJohnathan Mantey                 [SensorsAsyncResp, sensorNames, connections](
192395a3ecadSAnthony Wilson                     std::shared_ptr<
192495a3ecadSAnthony Wilson                         boost::container::flat_map<std::string, std::string>>
19258fb49dd6SShawn McCarney                         objectMgrPaths) {
1926de629b6eSShawn McCarney                     BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb enter";
1927adc4f0dbSShawn McCarney                     auto getInventoryItemsCb =
1928adc4f0dbSShawn McCarney                         [SensorsAsyncResp, sensorNames, connections,
1929adc4f0dbSShawn McCarney                          objectMgrPaths](
1930adc4f0dbSShawn McCarney                             std::shared_ptr<std::vector<InventoryItem>>
1931adc4f0dbSShawn McCarney                                 inventoryItems) {
1932adc4f0dbSShawn McCarney                             BMCWEB_LOG_DEBUG << "getInventoryItemsCb enter";
193349c53ac9SJohnathan Mantey                             // Get sensor data and store results in JSON
1934de629b6eSShawn McCarney                             getSensorData(SensorsAsyncResp, sensorNames,
1935adc4f0dbSShawn McCarney                                           connections, objectMgrPaths,
1936adc4f0dbSShawn McCarney                                           inventoryItems);
1937adc4f0dbSShawn McCarney                             BMCWEB_LOG_DEBUG << "getInventoryItemsCb exit";
1938adc4f0dbSShawn McCarney                         };
1939adc4f0dbSShawn McCarney 
1940adc4f0dbSShawn McCarney                     // Get inventory items associated with sensors
1941adc4f0dbSShawn McCarney                     getInventoryItems(SensorsAsyncResp, sensorNames,
1942adc4f0dbSShawn McCarney                                       objectMgrPaths,
1943adc4f0dbSShawn McCarney                                       std::move(getInventoryItemsCb));
1944adc4f0dbSShawn McCarney 
1945de629b6eSShawn McCarney                     BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb exit";
194608777fb0SLewanczyk, Dawid                 };
1947de629b6eSShawn McCarney 
194849c53ac9SJohnathan Mantey             // Get mapping from connection names to the DBus object
194949c53ac9SJohnathan Mantey             // paths that implement the ObjectManager interface
1950de629b6eSShawn McCarney             getObjectManagerPaths(SensorsAsyncResp,
1951de629b6eSShawn McCarney                                   std::move(getObjectManagerPathsCb));
195255c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "getConnectionCb exit";
195308777fb0SLewanczyk, Dawid         };
1954de629b6eSShawn McCarney 
1955de629b6eSShawn McCarney     // Get set of connections that provide sensor values
195695a3ecadSAnthony Wilson     getConnections(SensorsAsyncResp, sensorNames, std::move(getConnectionCb));
195795a3ecadSAnthony Wilson }
195895a3ecadSAnthony Wilson 
195995a3ecadSAnthony Wilson /**
196095a3ecadSAnthony Wilson  * @brief Entry point for retrieving sensors data related to requested
196195a3ecadSAnthony Wilson  *        chassis.
196295a3ecadSAnthony Wilson  * @param SensorsAsyncResp   Pointer to object holding response data
196395a3ecadSAnthony Wilson  */
196495a3ecadSAnthony Wilson void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
196595a3ecadSAnthony Wilson {
196695a3ecadSAnthony Wilson     BMCWEB_LOG_DEBUG << "getChassisData enter";
196795a3ecadSAnthony Wilson     auto getChassisCb =
196895a3ecadSAnthony Wilson         [SensorsAsyncResp](
196995a3ecadSAnthony Wilson             std::shared_ptr<boost::container::flat_set<std::string>>
197095a3ecadSAnthony Wilson                 sensorNames) {
197195a3ecadSAnthony Wilson             BMCWEB_LOG_DEBUG << "getChassisCb enter";
197295a3ecadSAnthony Wilson             processSensorList(SensorsAsyncResp, sensorNames);
197355c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "getChassisCb exit";
197408777fb0SLewanczyk, Dawid         };
19754f9a2130SJennifer Lee     SensorsAsyncResp->res.jsonValue["Redundancy"] = nlohmann::json::array();
197608777fb0SLewanczyk, Dawid 
197726f03899SShawn McCarney     // Get set of sensors in chassis
1978588c3f0dSKowalski, Kamil     getChassis(SensorsAsyncResp, std::move(getChassisCb));
197955c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisData exit";
1980271584abSEd Tanous }
198108777fb0SLewanczyk, Dawid 
1982413961deSRichard Marian Thomaiyar /**
198349c53ac9SJohnathan Mantey  * @brief Find the requested sensorName in the list of all sensors supplied by
198449c53ac9SJohnathan Mantey  * the chassis node
198549c53ac9SJohnathan Mantey  *
198649c53ac9SJohnathan Mantey  * @param sensorName   The sensor name supplied in the PATCH request
198749c53ac9SJohnathan Mantey  * @param sensorsList  The list of sensors managed by the chassis node
198849c53ac9SJohnathan Mantey  * @param sensorsModified  The list of sensors that were found as a result of
198949c53ac9SJohnathan Mantey  *                         repeated calls to this function
199049c53ac9SJohnathan Mantey  */
199149c53ac9SJohnathan Mantey bool findSensorNameUsingSensorPath(
19920a86febdSRichard Marian Thomaiyar     std::string_view sensorName,
199349c53ac9SJohnathan Mantey     boost::container::flat_set<std::string>& sensorsList,
199449c53ac9SJohnathan Mantey     boost::container::flat_set<std::string>& sensorsModified)
199549c53ac9SJohnathan Mantey {
19960a86febdSRichard Marian Thomaiyar     for (std::string_view chassisSensor : sensorsList)
199749c53ac9SJohnathan Mantey     {
19980a86febdSRichard Marian Thomaiyar         std::size_t pos = chassisSensor.rfind("/");
19990a86febdSRichard Marian Thomaiyar         if (pos >= (chassisSensor.size() - 1))
200049c53ac9SJohnathan Mantey         {
200149c53ac9SJohnathan Mantey             continue;
200249c53ac9SJohnathan Mantey         }
20030a86febdSRichard Marian Thomaiyar         std::string_view thisSensorName = chassisSensor.substr(pos + 1);
200449c53ac9SJohnathan Mantey         if (thisSensorName == sensorName)
200549c53ac9SJohnathan Mantey         {
200649c53ac9SJohnathan Mantey             sensorsModified.emplace(chassisSensor);
200749c53ac9SJohnathan Mantey             return true;
200849c53ac9SJohnathan Mantey         }
200949c53ac9SJohnathan Mantey     }
201049c53ac9SJohnathan Mantey     return false;
201149c53ac9SJohnathan Mantey }
201249c53ac9SJohnathan Mantey 
201349c53ac9SJohnathan Mantey /**
2014413961deSRichard Marian Thomaiyar  * @brief Entry point for overriding sensor values of given sensor
2015413961deSRichard Marian Thomaiyar  *
2016413961deSRichard Marian Thomaiyar  * @param res   response object
2017413961deSRichard Marian Thomaiyar  * @param req   request object
2018413961deSRichard Marian Thomaiyar  * @param params   parameter passed for CRUD
2019413961deSRichard Marian Thomaiyar  * @param typeList   TypeList of sensors for the resource queried
2020413961deSRichard Marian Thomaiyar  * @param chassisSubNode   Chassis Node for which the query has to happen
2021413961deSRichard Marian Thomaiyar  */
2022413961deSRichard Marian Thomaiyar void setSensorOverride(crow::Response& res, const crow::Request& req,
2023413961deSRichard Marian Thomaiyar                        const std::vector<std::string>& params,
202485e1424fSEd Tanous                        const std::vector<const char*> typeList,
2025413961deSRichard Marian Thomaiyar                        const std::string& chassisSubNode)
2026413961deSRichard Marian Thomaiyar {
2027413961deSRichard Marian Thomaiyar 
2028413961deSRichard Marian Thomaiyar     // TODO: Need to figure out dynamic way to restrict patch (Set Sensor
2029413961deSRichard Marian Thomaiyar     // override) based on another d-bus announcement to be more generic.
2030413961deSRichard Marian Thomaiyar     if (params.size() != 1)
2031413961deSRichard Marian Thomaiyar     {
2032413961deSRichard Marian Thomaiyar         messages::internalError(res);
2033413961deSRichard Marian Thomaiyar         res.end();
2034413961deSRichard Marian Thomaiyar         return;
2035413961deSRichard Marian Thomaiyar     }
2036f65af9e8SRichard Marian Thomaiyar 
2037f65af9e8SRichard Marian Thomaiyar     std::unordered_map<std::string, std::vector<nlohmann::json>> allCollections;
2038f65af9e8SRichard Marian Thomaiyar     std::optional<std::vector<nlohmann::json>> temperatureCollections;
2039f65af9e8SRichard Marian Thomaiyar     std::optional<std::vector<nlohmann::json>> fanCollections;
2040f65af9e8SRichard Marian Thomaiyar     std::vector<nlohmann::json> voltageCollections;
2041f65af9e8SRichard Marian Thomaiyar     BMCWEB_LOG_INFO << "setSensorOverride for subNode" << chassisSubNode
2042f65af9e8SRichard Marian Thomaiyar                     << "\n";
2043f65af9e8SRichard Marian Thomaiyar 
2044413961deSRichard Marian Thomaiyar     if (chassisSubNode == "Thermal")
2045413961deSRichard Marian Thomaiyar     {
2046f65af9e8SRichard Marian Thomaiyar         if (!json_util::readJson(req, res, "Temperatures",
2047f65af9e8SRichard Marian Thomaiyar                                  temperatureCollections, "Fans",
2048f65af9e8SRichard Marian Thomaiyar                                  fanCollections))
2049f65af9e8SRichard Marian Thomaiyar         {
2050f65af9e8SRichard Marian Thomaiyar             return;
2051f65af9e8SRichard Marian Thomaiyar         }
2052f65af9e8SRichard Marian Thomaiyar         if (!temperatureCollections && !fanCollections)
2053f65af9e8SRichard Marian Thomaiyar         {
2054f65af9e8SRichard Marian Thomaiyar             messages::resourceNotFound(res, "Thermal",
2055f65af9e8SRichard Marian Thomaiyar                                        "Temperatures / Voltages");
2056f65af9e8SRichard Marian Thomaiyar             res.end();
2057f65af9e8SRichard Marian Thomaiyar             return;
2058f65af9e8SRichard Marian Thomaiyar         }
2059f65af9e8SRichard Marian Thomaiyar         if (temperatureCollections)
2060f65af9e8SRichard Marian Thomaiyar         {
2061f65af9e8SRichard Marian Thomaiyar             allCollections.emplace("Temperatures",
2062f65af9e8SRichard Marian Thomaiyar                                    *std::move(temperatureCollections));
2063f65af9e8SRichard Marian Thomaiyar         }
2064f65af9e8SRichard Marian Thomaiyar         if (fanCollections)
2065f65af9e8SRichard Marian Thomaiyar         {
2066f65af9e8SRichard Marian Thomaiyar             allCollections.emplace("Fans", *std::move(fanCollections));
2067f65af9e8SRichard Marian Thomaiyar         }
2068413961deSRichard Marian Thomaiyar     }
2069413961deSRichard Marian Thomaiyar     else if (chassisSubNode == "Power")
2070413961deSRichard Marian Thomaiyar     {
2071f65af9e8SRichard Marian Thomaiyar         if (!json_util::readJson(req, res, "Voltages", voltageCollections))
2072f65af9e8SRichard Marian Thomaiyar         {
2073f65af9e8SRichard Marian Thomaiyar             return;
2074f65af9e8SRichard Marian Thomaiyar         }
2075f65af9e8SRichard Marian Thomaiyar         allCollections.emplace("Voltages", std::move(voltageCollections));
2076413961deSRichard Marian Thomaiyar     }
2077413961deSRichard Marian Thomaiyar     else
2078413961deSRichard Marian Thomaiyar     {
2079413961deSRichard Marian Thomaiyar         res.result(boost::beast::http::status::not_found);
2080413961deSRichard Marian Thomaiyar         res.end();
2081413961deSRichard Marian Thomaiyar         return;
2082413961deSRichard Marian Thomaiyar     }
2083413961deSRichard Marian Thomaiyar 
2084f65af9e8SRichard Marian Thomaiyar     const char* propertyValueName;
2085f65af9e8SRichard Marian Thomaiyar     std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
2086413961deSRichard Marian Thomaiyar     std::string memberId;
2087413961deSRichard Marian Thomaiyar     double value;
2088f65af9e8SRichard Marian Thomaiyar     for (auto& collectionItems : allCollections)
2089f65af9e8SRichard Marian Thomaiyar     {
2090f65af9e8SRichard Marian Thomaiyar         if (collectionItems.first == "Temperatures")
2091f65af9e8SRichard Marian Thomaiyar         {
2092f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingCelsius";
2093f65af9e8SRichard Marian Thomaiyar         }
2094f65af9e8SRichard Marian Thomaiyar         else if (collectionItems.first == "Fans")
2095f65af9e8SRichard Marian Thomaiyar         {
2096f65af9e8SRichard Marian Thomaiyar             propertyValueName = "Reading";
2097f65af9e8SRichard Marian Thomaiyar         }
2098f65af9e8SRichard Marian Thomaiyar         else
2099f65af9e8SRichard Marian Thomaiyar         {
2100f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingVolts";
2101f65af9e8SRichard Marian Thomaiyar         }
2102f65af9e8SRichard Marian Thomaiyar         for (auto& item : collectionItems.second)
2103f65af9e8SRichard Marian Thomaiyar         {
2104f65af9e8SRichard Marian Thomaiyar             if (!json_util::readJson(item, res, "MemberId", memberId,
2105413961deSRichard Marian Thomaiyar                                      propertyValueName, value))
2106413961deSRichard Marian Thomaiyar             {
2107413961deSRichard Marian Thomaiyar                 return;
2108413961deSRichard Marian Thomaiyar             }
2109f65af9e8SRichard Marian Thomaiyar             overrideMap.emplace(memberId,
2110f65af9e8SRichard Marian Thomaiyar                                 std::make_pair(value, collectionItems.first));
2111f65af9e8SRichard Marian Thomaiyar         }
2112f65af9e8SRichard Marian Thomaiyar     }
2113413961deSRichard Marian Thomaiyar     const std::string& chassisName = params[0];
2114413961deSRichard Marian Thomaiyar     auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
2115413961deSRichard Marian Thomaiyar         res, chassisName, typeList, chassisSubNode);
211649c53ac9SJohnathan Mantey     auto getChassisSensorListCb = [sensorAsyncResp,
211749c53ac9SJohnathan Mantey                                    overrideMap](const std::shared_ptr<
211849c53ac9SJohnathan Mantey                                                 boost::container::flat_set<
211949c53ac9SJohnathan Mantey                                                     std::string>>
212049c53ac9SJohnathan Mantey                                                     sensorsList) {
212149c53ac9SJohnathan Mantey         // Match sensor names in the PATCH request to those managed by the
212249c53ac9SJohnathan Mantey         // chassis node
212349c53ac9SJohnathan Mantey         const std::shared_ptr<boost::container::flat_set<std::string>>
212449c53ac9SJohnathan Mantey             sensorNames =
212549c53ac9SJohnathan Mantey                 std::make_shared<boost::container::flat_set<std::string>>();
2126f65af9e8SRichard Marian Thomaiyar         for (const auto& item : overrideMap)
2127413961deSRichard Marian Thomaiyar         {
2128f65af9e8SRichard Marian Thomaiyar             const auto& sensor = item.first;
212949c53ac9SJohnathan Mantey             if (!findSensorNameUsingSensorPath(sensor, *sensorsList,
213049c53ac9SJohnathan Mantey                                                *sensorNames))
2131f65af9e8SRichard Marian Thomaiyar             {
2132f65af9e8SRichard Marian Thomaiyar                 BMCWEB_LOG_INFO << "Unable to find memberId " << item.first;
2133413961deSRichard Marian Thomaiyar                 messages::resourceNotFound(sensorAsyncResp->res,
2134f65af9e8SRichard Marian Thomaiyar                                            item.second.second, item.first);
2135413961deSRichard Marian Thomaiyar                 return;
2136413961deSRichard Marian Thomaiyar             }
2137f65af9e8SRichard Marian Thomaiyar         }
2138413961deSRichard Marian Thomaiyar         // Get the connection to which the memberId belongs
2139413961deSRichard Marian Thomaiyar         auto getObjectsWithConnectionCb =
2140f65af9e8SRichard Marian Thomaiyar             [sensorAsyncResp, overrideMap](
2141413961deSRichard Marian Thomaiyar                 const boost::container::flat_set<std::string>& connections,
2142413961deSRichard Marian Thomaiyar                 const std::set<std::pair<std::string, std::string>>&
2143413961deSRichard Marian Thomaiyar                     objectsWithConnection) {
2144f65af9e8SRichard Marian Thomaiyar                 if (objectsWithConnection.size() != overrideMap.size())
2145413961deSRichard Marian Thomaiyar                 {
2146413961deSRichard Marian Thomaiyar                     BMCWEB_LOG_INFO
2147f65af9e8SRichard Marian Thomaiyar                         << "Unable to find all objects with proper connection "
2148f65af9e8SRichard Marian Thomaiyar                         << objectsWithConnection.size() << " requested "
2149f65af9e8SRichard Marian Thomaiyar                         << overrideMap.size() << "\n";
2150413961deSRichard Marian Thomaiyar                     messages::resourceNotFound(
2151413961deSRichard Marian Thomaiyar                         sensorAsyncResp->res,
2152413961deSRichard Marian Thomaiyar                         sensorAsyncResp->chassisSubNode == "Thermal"
2153413961deSRichard Marian Thomaiyar                             ? "Temperatures"
2154413961deSRichard Marian Thomaiyar                             : "Voltages",
2155f65af9e8SRichard Marian Thomaiyar                         "Count");
2156f65af9e8SRichard Marian Thomaiyar                     return;
2157f65af9e8SRichard Marian Thomaiyar                 }
2158f65af9e8SRichard Marian Thomaiyar                 for (const auto& item : objectsWithConnection)
2159f65af9e8SRichard Marian Thomaiyar                 {
2160f65af9e8SRichard Marian Thomaiyar 
2161f65af9e8SRichard Marian Thomaiyar                     auto lastPos = item.first.rfind('/');
2162f65af9e8SRichard Marian Thomaiyar                     if (lastPos == std::string::npos)
2163f65af9e8SRichard Marian Thomaiyar                     {
2164f65af9e8SRichard Marian Thomaiyar                         messages::internalError(sensorAsyncResp->res);
2165f65af9e8SRichard Marian Thomaiyar                         return;
2166f65af9e8SRichard Marian Thomaiyar                     }
2167f65af9e8SRichard Marian Thomaiyar                     std::string sensorName = item.first.substr(lastPos + 1);
2168f65af9e8SRichard Marian Thomaiyar 
2169f65af9e8SRichard Marian Thomaiyar                     const auto& iterator = overrideMap.find(sensorName);
2170f65af9e8SRichard Marian Thomaiyar                     if (iterator == overrideMap.end())
2171f65af9e8SRichard Marian Thomaiyar                     {
2172f65af9e8SRichard Marian Thomaiyar                         BMCWEB_LOG_INFO << "Unable to find sensor object"
2173f65af9e8SRichard Marian Thomaiyar                                         << item.first << "\n";
2174f65af9e8SRichard Marian Thomaiyar                         messages::internalError(sensorAsyncResp->res);
2175413961deSRichard Marian Thomaiyar                         return;
2176413961deSRichard Marian Thomaiyar                     }
2177413961deSRichard Marian Thomaiyar                     crow::connections::systemBus->async_method_call(
2178f65af9e8SRichard Marian Thomaiyar                         [sensorAsyncResp](const boost::system::error_code ec) {
2179413961deSRichard Marian Thomaiyar                             if (ec)
2180413961deSRichard Marian Thomaiyar                             {
2181413961deSRichard Marian Thomaiyar                                 BMCWEB_LOG_DEBUG
2182f65af9e8SRichard Marian Thomaiyar                                     << "setOverrideValueStatus DBUS error: "
2183413961deSRichard Marian Thomaiyar                                     << ec;
2184413961deSRichard Marian Thomaiyar                                 messages::internalError(sensorAsyncResp->res);
2185413961deSRichard Marian Thomaiyar                                 return;
2186413961deSRichard Marian Thomaiyar                             }
2187413961deSRichard Marian Thomaiyar                         },
2188f65af9e8SRichard Marian Thomaiyar                         item.second, item.first,
2189413961deSRichard Marian Thomaiyar                         "org.freedesktop.DBus.Properties", "Set",
2190413961deSRichard Marian Thomaiyar                         "xyz.openbmc_project.Sensor.Value", "Value",
2191f65af9e8SRichard Marian Thomaiyar                         sdbusplus::message::variant<double>(
2192f65af9e8SRichard Marian Thomaiyar                             iterator->second.first));
2193f65af9e8SRichard Marian Thomaiyar                 }
2194413961deSRichard Marian Thomaiyar             };
2195413961deSRichard Marian Thomaiyar         // Get object with connection for the given sensor name
2196413961deSRichard Marian Thomaiyar         getObjectsWithConnection(sensorAsyncResp, sensorNames,
2197413961deSRichard Marian Thomaiyar                                  std::move(getObjectsWithConnectionCb));
2198413961deSRichard Marian Thomaiyar     };
2199413961deSRichard Marian Thomaiyar     // get full sensor list for the given chassisId and cross verify the sensor.
2200413961deSRichard Marian Thomaiyar     getChassis(sensorAsyncResp, std::move(getChassisSensorListCb));
2201413961deSRichard Marian Thomaiyar }
2202413961deSRichard Marian Thomaiyar 
220395a3ecadSAnthony Wilson class SensorCollection : public Node
220495a3ecadSAnthony Wilson {
220595a3ecadSAnthony Wilson   public:
220695a3ecadSAnthony Wilson     SensorCollection(CrowApp& app) :
220795a3ecadSAnthony Wilson         Node(app, "/redfish/v1/Chassis/<str>/Sensors", std::string())
220895a3ecadSAnthony Wilson     {
220995a3ecadSAnthony Wilson         entityPrivileges = {
221095a3ecadSAnthony Wilson             {boost::beast::http::verb::get, {{"Login"}}},
221195a3ecadSAnthony Wilson             {boost::beast::http::verb::head, {{"Login"}}},
221295a3ecadSAnthony Wilson             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
221395a3ecadSAnthony Wilson             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
221495a3ecadSAnthony Wilson             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
221595a3ecadSAnthony Wilson             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
221695a3ecadSAnthony Wilson     }
221795a3ecadSAnthony Wilson 
221895a3ecadSAnthony Wilson   private:
221995a3ecadSAnthony Wilson     std::vector<const char*> typeList = {
222095a3ecadSAnthony Wilson         "/xyz/openbmc_project/sensors/power",
222195a3ecadSAnthony Wilson         "/xyz/openbmc_project/sensors/current"};
222295a3ecadSAnthony Wilson     void doGet(crow::Response& res, const crow::Request& req,
222395a3ecadSAnthony Wilson                const std::vector<std::string>& params) override
222495a3ecadSAnthony Wilson     {
222595a3ecadSAnthony Wilson         BMCWEB_LOG_DEBUG << "SensorCollection doGet enter";
222695a3ecadSAnthony Wilson         if (params.size() != 1)
222795a3ecadSAnthony Wilson         {
222895a3ecadSAnthony Wilson             BMCWEB_LOG_DEBUG << "SensorCollection doGet param size < 1";
222995a3ecadSAnthony Wilson             messages::internalError(res);
223095a3ecadSAnthony Wilson             res.end();
223195a3ecadSAnthony Wilson             return;
223295a3ecadSAnthony Wilson         }
223395a3ecadSAnthony Wilson 
223495a3ecadSAnthony Wilson         const std::string& chassisId = params[0];
223595a3ecadSAnthony Wilson         std::shared_ptr<SensorsAsyncResp> asyncResp =
223695a3ecadSAnthony Wilson             std::make_shared<SensorsAsyncResp>(res, chassisId, typeList,
223795a3ecadSAnthony Wilson                                                "Sensors");
223895a3ecadSAnthony Wilson 
223995a3ecadSAnthony Wilson         auto getChassisCb =
224095a3ecadSAnthony Wilson             [asyncResp](std::shared_ptr<boost::container::flat_set<std::string>>
224195a3ecadSAnthony Wilson                             sensorNames) {
224295a3ecadSAnthony Wilson                 BMCWEB_LOG_DEBUG << "getChassisCb enter";
224395a3ecadSAnthony Wilson 
224495a3ecadSAnthony Wilson                 nlohmann::json& entriesArray =
224595a3ecadSAnthony Wilson                     asyncResp->res.jsonValue["Members"];
224695a3ecadSAnthony Wilson                 for (auto& sensor : *sensorNames)
224795a3ecadSAnthony Wilson                 {
224895a3ecadSAnthony Wilson                     BMCWEB_LOG_DEBUG << "Adding sensor: " << sensor;
224995a3ecadSAnthony Wilson 
225095a3ecadSAnthony Wilson                     std::size_t lastPos = sensor.rfind("/");
225195a3ecadSAnthony Wilson                     if (lastPos == std::string::npos ||
225295a3ecadSAnthony Wilson                         lastPos + 1 >= sensor.size())
225395a3ecadSAnthony Wilson                     {
225495a3ecadSAnthony Wilson                         BMCWEB_LOG_ERROR << "Invalid sensor path: " << sensor;
225595a3ecadSAnthony Wilson                         messages::internalError(asyncResp->res);
225695a3ecadSAnthony Wilson                         return;
225795a3ecadSAnthony Wilson                     }
225895a3ecadSAnthony Wilson                     std::string sensorName = sensor.substr(lastPos + 1);
225995a3ecadSAnthony Wilson                     entriesArray.push_back(
226095a3ecadSAnthony Wilson                         {{"@odata.id",
226195a3ecadSAnthony Wilson                           "/redfish/v1/Chassis/" + asyncResp->chassisId + "/" +
226295a3ecadSAnthony Wilson                               asyncResp->chassisSubNode + "/" + sensorName}});
226395a3ecadSAnthony Wilson                 }
226495a3ecadSAnthony Wilson 
226595a3ecadSAnthony Wilson                 asyncResp->res.jsonValue["Members@odata.count"] =
226695a3ecadSAnthony Wilson                     entriesArray.size();
226795a3ecadSAnthony Wilson                 BMCWEB_LOG_DEBUG << "getChassisCb exit";
226895a3ecadSAnthony Wilson             };
226995a3ecadSAnthony Wilson 
227095a3ecadSAnthony Wilson         // Get set of sensors in chassis
227195a3ecadSAnthony Wilson         getChassis(asyncResp, std::move(getChassisCb));
227295a3ecadSAnthony Wilson         BMCWEB_LOG_DEBUG << "SensorCollection doGet exit";
227395a3ecadSAnthony Wilson     }
227495a3ecadSAnthony Wilson };
227595a3ecadSAnthony Wilson 
227695a3ecadSAnthony Wilson class Sensor : public Node
227795a3ecadSAnthony Wilson {
227895a3ecadSAnthony Wilson   public:
227995a3ecadSAnthony Wilson     Sensor(CrowApp& app) :
228095a3ecadSAnthony Wilson         Node(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/", std::string(),
228195a3ecadSAnthony Wilson              std::string())
228295a3ecadSAnthony Wilson     {
228395a3ecadSAnthony Wilson         entityPrivileges = {
228495a3ecadSAnthony Wilson             {boost::beast::http::verb::get, {{"Login"}}},
228595a3ecadSAnthony Wilson             {boost::beast::http::verb::head, {{"Login"}}},
228695a3ecadSAnthony Wilson             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
228795a3ecadSAnthony Wilson             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
228895a3ecadSAnthony Wilson             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
228995a3ecadSAnthony Wilson             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
229095a3ecadSAnthony Wilson     }
229195a3ecadSAnthony Wilson 
229295a3ecadSAnthony Wilson   private:
229395a3ecadSAnthony Wilson     void doGet(crow::Response& res, const crow::Request& req,
229495a3ecadSAnthony Wilson                const std::vector<std::string>& params) override
229595a3ecadSAnthony Wilson     {
229695a3ecadSAnthony Wilson         BMCWEB_LOG_DEBUG << "Sensor doGet enter";
229795a3ecadSAnthony Wilson         if (params.size() != 2)
229895a3ecadSAnthony Wilson         {
229995a3ecadSAnthony Wilson             BMCWEB_LOG_DEBUG << "Sensor doGet param size < 2";
230095a3ecadSAnthony Wilson             messages::internalError(res);
230195a3ecadSAnthony Wilson             res.end();
230295a3ecadSAnthony Wilson             return;
230395a3ecadSAnthony Wilson         }
230495a3ecadSAnthony Wilson         const std::string& chassisId = params[0];
230595a3ecadSAnthony Wilson         std::shared_ptr<SensorsAsyncResp> asyncResp =
230695a3ecadSAnthony Wilson             std::make_shared<SensorsAsyncResp>(
230795a3ecadSAnthony Wilson                 res, chassisId, std::vector<const char*>(), "Sensors");
230895a3ecadSAnthony Wilson 
230995a3ecadSAnthony Wilson         const std::string& sensorName = params[1];
231095a3ecadSAnthony Wilson         const std::array<const char*, 1> interfaces = {
231195a3ecadSAnthony Wilson             "xyz.openbmc_project.Sensor.Value"};
231295a3ecadSAnthony Wilson 
231395a3ecadSAnthony Wilson         // Get a list of all of the sensors that implement Sensor.Value
231495a3ecadSAnthony Wilson         // and get the path and service name associated with the sensor
231595a3ecadSAnthony Wilson         crow::connections::systemBus->async_method_call(
231695a3ecadSAnthony Wilson             [asyncResp, sensorName](const boost::system::error_code ec,
231795a3ecadSAnthony Wilson                                     const GetSubTreeType& subtree) {
231895a3ecadSAnthony Wilson                 BMCWEB_LOG_DEBUG << "respHandler1 enter";
231995a3ecadSAnthony Wilson                 if (ec)
232095a3ecadSAnthony Wilson                 {
232195a3ecadSAnthony Wilson                     messages::internalError(asyncResp->res);
232295a3ecadSAnthony Wilson                     BMCWEB_LOG_ERROR << "Sensor getSensorPaths resp_handler: "
232395a3ecadSAnthony Wilson                                      << "Dbus error " << ec;
232495a3ecadSAnthony Wilson                     return;
232595a3ecadSAnthony Wilson                 }
232695a3ecadSAnthony Wilson 
232795a3ecadSAnthony Wilson                 GetSubTreeType::const_iterator it = std::find_if(
232895a3ecadSAnthony Wilson                     subtree.begin(), subtree.end(),
232995a3ecadSAnthony Wilson                     [sensorName](
233095a3ecadSAnthony Wilson                         const std::pair<
233195a3ecadSAnthony Wilson                             std::string,
233295a3ecadSAnthony Wilson                             std::vector<std::pair<std::string,
233395a3ecadSAnthony Wilson                                                   std::vector<std::string>>>>&
233495a3ecadSAnthony Wilson                             object) {
233595a3ecadSAnthony Wilson                         std::string_view sensor = object.first;
233695a3ecadSAnthony Wilson                         std::size_t lastPos = sensor.rfind("/");
233795a3ecadSAnthony Wilson                         if (lastPos == std::string::npos ||
233895a3ecadSAnthony Wilson                             lastPos + 1 >= sensor.size())
233995a3ecadSAnthony Wilson                         {
234095a3ecadSAnthony Wilson                             BMCWEB_LOG_ERROR << "Invalid sensor path: "
234195a3ecadSAnthony Wilson                                              << sensor;
234295a3ecadSAnthony Wilson                             return false;
234395a3ecadSAnthony Wilson                         }
234495a3ecadSAnthony Wilson                         std::string_view name = sensor.substr(lastPos + 1);
234595a3ecadSAnthony Wilson 
234695a3ecadSAnthony Wilson                         return name == sensorName;
234795a3ecadSAnthony Wilson                     });
234895a3ecadSAnthony Wilson 
234995a3ecadSAnthony Wilson                 if (it == subtree.end())
235095a3ecadSAnthony Wilson                 {
235195a3ecadSAnthony Wilson                     BMCWEB_LOG_ERROR << "Could not find path for sensor: "
235295a3ecadSAnthony Wilson                                      << sensorName;
235395a3ecadSAnthony Wilson                     messages::resourceNotFound(asyncResp->res, "Sensor",
235495a3ecadSAnthony Wilson                                                sensorName);
235595a3ecadSAnthony Wilson                     return;
235695a3ecadSAnthony Wilson                 }
235795a3ecadSAnthony Wilson                 std::string_view sensorPath = (*it).first;
235895a3ecadSAnthony Wilson                 BMCWEB_LOG_DEBUG << "Found sensor path for sensor '"
235995a3ecadSAnthony Wilson                                  << sensorName << "': " << sensorPath;
236095a3ecadSAnthony Wilson 
236195a3ecadSAnthony Wilson                 const std::shared_ptr<boost::container::flat_set<std::string>>
236295a3ecadSAnthony Wilson                     sensorList = std::make_shared<
236395a3ecadSAnthony Wilson                         boost::container::flat_set<std::string>>();
236495a3ecadSAnthony Wilson 
236595a3ecadSAnthony Wilson                 sensorList->emplace(sensorPath);
236695a3ecadSAnthony Wilson                 processSensorList(asyncResp, sensorList);
236795a3ecadSAnthony Wilson                 BMCWEB_LOG_DEBUG << "respHandler1 exit";
236895a3ecadSAnthony Wilson             },
236995a3ecadSAnthony Wilson             "xyz.openbmc_project.ObjectMapper",
237095a3ecadSAnthony Wilson             "/xyz/openbmc_project/object_mapper",
237195a3ecadSAnthony Wilson             "xyz.openbmc_project.ObjectMapper", "GetSubTree",
237295a3ecadSAnthony Wilson             "/xyz/openbmc_project/sensors", 2, interfaces);
237395a3ecadSAnthony Wilson     }
237495a3ecadSAnthony Wilson };
237595a3ecadSAnthony Wilson 
237608777fb0SLewanczyk, Dawid } // namespace redfish
2377