xref: /openbmc/bmcweb/features/redfish/lib/sensors.hpp (revision 8fb49dd60624afe750d748b1a4c206bda2f9950d)
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 
1808777fb0SLewanczyk, Dawid #include <math.h>
191abe55efSEd Tanous 
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>
241abe55efSEd Tanous #include <dbus_singleton.hpp>
25413961deSRichard Marian Thomaiyar #include <utils/json_utils.hpp>
26abf2add6SEd Tanous #include <variant>
2708777fb0SLewanczyk, Dawid 
281abe55efSEd Tanous namespace redfish
291abe55efSEd Tanous {
3008777fb0SLewanczyk, Dawid 
3108777fb0SLewanczyk, Dawid using GetSubTreeType = std::vector<
3208777fb0SLewanczyk, Dawid     std::pair<std::string,
3308777fb0SLewanczyk, Dawid               std::vector<std::pair<std::string, std::vector<std::string>>>>>;
3408777fb0SLewanczyk, Dawid 
35028f7ebcSEddie James using SensorVariant = std::variant<int64_t, double, uint32_t, bool>;
36aa2e59c1SEd Tanous 
3708777fb0SLewanczyk, Dawid using ManagedObjectsVectorType = std::vector<std::pair<
38aa2e59c1SEd Tanous     sdbusplus::message::object_path,
3908777fb0SLewanczyk, Dawid     boost::container::flat_map<
40aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>>>;
4108777fb0SLewanczyk, Dawid 
4208777fb0SLewanczyk, Dawid /**
43588c3f0dSKowalski, Kamil  * SensorsAsyncResp
4408777fb0SLewanczyk, Dawid  * Gathers data needed for response processing after async calls are done
4508777fb0SLewanczyk, Dawid  */
461abe55efSEd Tanous class SensorsAsyncResp
471abe55efSEd Tanous {
4808777fb0SLewanczyk, Dawid   public:
4955c7b7a2SEd Tanous     SensorsAsyncResp(crow::Response& response, const std::string& chassisId,
50b01bf299SEd Tanous                      const std::initializer_list<const char*> types,
512474adfaSEd Tanous                      const std::string& subNode) :
5243b761d0SEd Tanous         res(response),
5343b761d0SEd Tanous         chassisId(chassisId), types(types), chassisSubNode(subNode)
541abe55efSEd Tanous     {
5508777fb0SLewanczyk, Dawid     }
5608777fb0SLewanczyk, Dawid 
571abe55efSEd Tanous     ~SensorsAsyncResp()
581abe55efSEd Tanous     {
591abe55efSEd Tanous         if (res.result() == boost::beast::http::status::internal_server_error)
601abe55efSEd Tanous         {
611abe55efSEd Tanous             // Reset the json object to clear out any data that made it in
621abe55efSEd Tanous             // before the error happened todo(ed) handle error condition with
631abe55efSEd Tanous             // proper code
6455c7b7a2SEd Tanous             res.jsonValue = nlohmann::json::object();
6508777fb0SLewanczyk, Dawid         }
6608777fb0SLewanczyk, Dawid         res.end();
6708777fb0SLewanczyk, Dawid     }
68588c3f0dSKowalski, Kamil 
6955c7b7a2SEd Tanous     crow::Response& res;
70588c3f0dSKowalski, Kamil     std::string chassisId{};
7108777fb0SLewanczyk, Dawid     const std::vector<const char*> types;
722474adfaSEd Tanous     std::string chassisSubNode{};
7308777fb0SLewanczyk, Dawid };
7408777fb0SLewanczyk, Dawid 
7508777fb0SLewanczyk, Dawid /**
76413961deSRichard Marian Thomaiyar  * @brief Get objects with connection necessary for sensors
77588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp Pointer to object holding response data
7808777fb0SLewanczyk, Dawid  * @param sensorNames Sensors retrieved from chassis
7908777fb0SLewanczyk, Dawid  * @param callback Callback for processing gathered connections
8008777fb0SLewanczyk, Dawid  */
8108777fb0SLewanczyk, Dawid template <typename Callback>
82413961deSRichard Marian Thomaiyar void getObjectsWithConnection(
83413961deSRichard Marian Thomaiyar     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
8449c53ac9SJohnathan Mantey     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
851abe55efSEd Tanous     Callback&& callback)
861abe55efSEd Tanous {
87413961deSRichard Marian Thomaiyar     BMCWEB_LOG_DEBUG << "getObjectsWithConnection enter";
8803b5bae3SJames Feist     const std::string path = "/xyz/openbmc_project/sensors";
8908777fb0SLewanczyk, Dawid     const std::array<std::string, 1> interfaces = {
9008777fb0SLewanczyk, Dawid         "xyz.openbmc_project.Sensor.Value"};
9108777fb0SLewanczyk, Dawid 
9208777fb0SLewanczyk, Dawid     // Response handler for parsing objects subtree
931abe55efSEd Tanous     auto respHandler = [callback{std::move(callback)}, SensorsAsyncResp,
941abe55efSEd Tanous                         sensorNames](const boost::system::error_code ec,
951abe55efSEd Tanous                                      const GetSubTreeType& subtree) {
96413961deSRichard Marian Thomaiyar         BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler enter";
971abe55efSEd Tanous         if (ec)
981abe55efSEd Tanous         {
995f7d88c4SEd Tanous             messages::internalError(SensorsAsyncResp->res);
100413961deSRichard Marian Thomaiyar             BMCWEB_LOG_ERROR
101413961deSRichard Marian Thomaiyar                 << "getObjectsWithConnection resp_handler: Dbus error " << ec;
10208777fb0SLewanczyk, Dawid             return;
10308777fb0SLewanczyk, Dawid         }
10408777fb0SLewanczyk, Dawid 
10555c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
10608777fb0SLewanczyk, Dawid 
10708777fb0SLewanczyk, Dawid         // Make unique list of connections only for requested sensor types and
10808777fb0SLewanczyk, Dawid         // found in the chassis
10908777fb0SLewanczyk, Dawid         boost::container::flat_set<std::string> connections;
110413961deSRichard Marian Thomaiyar         std::set<std::pair<std::string, std::string>> objectsWithConnection;
1111abe55efSEd Tanous         // Intrinsic to avoid malloc.  Most systems will have < 8 sensor
1121abe55efSEd Tanous         // producers
11308777fb0SLewanczyk, Dawid         connections.reserve(8);
11408777fb0SLewanczyk, Dawid 
11549c53ac9SJohnathan Mantey         BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames->size();
11649c53ac9SJohnathan Mantey         for (const std::string& tsensor : *sensorNames)
1171abe55efSEd Tanous         {
11855c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor;
11908777fb0SLewanczyk, Dawid         }
12008777fb0SLewanczyk, Dawid 
12108777fb0SLewanczyk, Dawid         for (const std::pair<
12208777fb0SLewanczyk, Dawid                  std::string,
12308777fb0SLewanczyk, Dawid                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
1241abe55efSEd Tanous                  object : subtree)
1251abe55efSEd Tanous         {
12649c53ac9SJohnathan Mantey             if (sensorNames->find(object.first) != sensorNames->end())
1271abe55efSEd Tanous             {
12849c53ac9SJohnathan Mantey                 for (const std::pair<std::string, std::vector<std::string>>&
1291abe55efSEd Tanous                          objData : object.second)
1301abe55efSEd Tanous                 {
13149c53ac9SJohnathan Mantey                     BMCWEB_LOG_DEBUG << "Adding connection: " << objData.first;
13208777fb0SLewanczyk, Dawid                     connections.insert(objData.first);
133de629b6eSShawn McCarney                     objectsWithConnection.insert(
134de629b6eSShawn McCarney                         std::make_pair(object.first, objData.first));
13508777fb0SLewanczyk, Dawid                 }
13608777fb0SLewanczyk, Dawid             }
13708777fb0SLewanczyk, Dawid         }
13855c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections";
139413961deSRichard Marian Thomaiyar         callback(std::move(connections), std::move(objectsWithConnection));
140413961deSRichard Marian Thomaiyar         BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler exit";
14108777fb0SLewanczyk, Dawid     };
14208777fb0SLewanczyk, Dawid     // Make call to ObjectMapper to find all sensors objects
14355c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
14455c7b7a2SEd Tanous         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
1451abe55efSEd Tanous         "/xyz/openbmc_project/object_mapper",
1461abe55efSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 2, interfaces);
147413961deSRichard Marian Thomaiyar     BMCWEB_LOG_DEBUG << "getObjectsWithConnection exit";
148413961deSRichard Marian Thomaiyar }
149413961deSRichard Marian Thomaiyar 
150413961deSRichard Marian Thomaiyar /**
151413961deSRichard Marian Thomaiyar  * @brief Create connections necessary for sensors
152413961deSRichard Marian Thomaiyar  * @param SensorsAsyncResp Pointer to object holding response data
153413961deSRichard Marian Thomaiyar  * @param sensorNames Sensors retrieved from chassis
154413961deSRichard Marian Thomaiyar  * @param callback Callback for processing gathered connections
155413961deSRichard Marian Thomaiyar  */
156413961deSRichard Marian Thomaiyar template <typename Callback>
15749c53ac9SJohnathan Mantey void getConnections(
15849c53ac9SJohnathan Mantey     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
15949c53ac9SJohnathan Mantey     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
160413961deSRichard Marian Thomaiyar     Callback&& callback)
161413961deSRichard Marian Thomaiyar {
162413961deSRichard Marian Thomaiyar     auto objectsWithConnectionCb =
163413961deSRichard Marian Thomaiyar         [callback](const boost::container::flat_set<std::string>& connections,
164413961deSRichard Marian Thomaiyar                    const std::set<std::pair<std::string, std::string>>&
165413961deSRichard Marian Thomaiyar                        objectsWithConnection) {
166413961deSRichard Marian Thomaiyar             callback(std::move(connections));
167413961deSRichard Marian Thomaiyar         };
168413961deSRichard Marian Thomaiyar     getObjectsWithConnection(SensorsAsyncResp, sensorNames,
169413961deSRichard Marian Thomaiyar                              std::move(objectsWithConnectionCb));
17008777fb0SLewanczyk, Dawid }
17108777fb0SLewanczyk, Dawid 
17208777fb0SLewanczyk, Dawid /**
17349c53ac9SJohnathan Mantey  * @brief Shrinks the list of sensors for processing
17449c53ac9SJohnathan Mantey  * @param SensorsAysncResp  The class holding the Redfish response
17549c53ac9SJohnathan Mantey  * @param allSensors  A list of all the sensors associated to the
17649c53ac9SJohnathan Mantey  * chassis element (i.e. baseboard, front panel, etc...)
17749c53ac9SJohnathan Mantey  * @param activeSensors A list that is a reduction of the incoming
17849c53ac9SJohnathan Mantey  * allSensors list.  Eliminate Thermal sensors when a Power request is
17949c53ac9SJohnathan Mantey  * made, and eliminate Power sensors when a Thermal request is made.
18049c53ac9SJohnathan Mantey  */
18149c53ac9SJohnathan Mantey void reduceSensorList(
18249c53ac9SJohnathan Mantey     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
18349c53ac9SJohnathan Mantey     const std::vector<std::string>* allSensors,
18449c53ac9SJohnathan Mantey     std::shared_ptr<boost::container::flat_set<std::string>> activeSensors)
18549c53ac9SJohnathan Mantey {
18649c53ac9SJohnathan Mantey     if (SensorsAsyncResp == nullptr)
18749c53ac9SJohnathan Mantey     {
18849c53ac9SJohnathan Mantey         return;
18949c53ac9SJohnathan Mantey     }
19049c53ac9SJohnathan Mantey     if ((allSensors == nullptr) || (activeSensors == nullptr))
19149c53ac9SJohnathan Mantey     {
19249c53ac9SJohnathan Mantey         messages::resourceNotFound(
19349c53ac9SJohnathan Mantey             SensorsAsyncResp->res, SensorsAsyncResp->chassisSubNode,
19449c53ac9SJohnathan Mantey             SensorsAsyncResp->chassisSubNode == "Thermal" ? "Temperatures"
19549c53ac9SJohnathan Mantey                                                           : "Voltages");
19649c53ac9SJohnathan Mantey 
19749c53ac9SJohnathan Mantey         return;
19849c53ac9SJohnathan Mantey     }
19949c53ac9SJohnathan Mantey     if (allSensors->empty())
20049c53ac9SJohnathan Mantey     {
20149c53ac9SJohnathan Mantey         // Nothing to do, the activeSensors object is also empty
20249c53ac9SJohnathan Mantey         return;
20349c53ac9SJohnathan Mantey     }
20449c53ac9SJohnathan Mantey 
20549c53ac9SJohnathan Mantey     for (const char* type : SensorsAsyncResp->types)
20649c53ac9SJohnathan Mantey     {
20749c53ac9SJohnathan Mantey         for (const std::string& sensor : *allSensors)
20849c53ac9SJohnathan Mantey         {
20949c53ac9SJohnathan Mantey             if (boost::starts_with(sensor, type))
21049c53ac9SJohnathan Mantey             {
21149c53ac9SJohnathan Mantey                 activeSensors->emplace(sensor);
21249c53ac9SJohnathan Mantey             }
21349c53ac9SJohnathan Mantey         }
21449c53ac9SJohnathan Mantey     }
21549c53ac9SJohnathan Mantey }
21649c53ac9SJohnathan Mantey 
21749c53ac9SJohnathan Mantey /**
21808777fb0SLewanczyk, Dawid  * @brief Retrieves requested chassis sensors and redundancy data from DBus .
219588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
22008777fb0SLewanczyk, Dawid  * @param callback  Callback for next step in gathered sensor processing
22108777fb0SLewanczyk, Dawid  */
22208777fb0SLewanczyk, Dawid template <typename Callback>
22349c53ac9SJohnathan Mantey void getChassis(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
2241abe55efSEd Tanous                 Callback&& callback)
2251abe55efSEd Tanous {
22655c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis enter";
22749c53ac9SJohnathan Mantey     const std::array<const char*, 3> interfaces = {
22849c53ac9SJohnathan Mantey         "xyz.openbmc_project.Inventory.Item.Board",
22949c53ac9SJohnathan Mantey         "xyz.openbmc_project.Inventory.Item.Chassis",
23049c53ac9SJohnathan Mantey         "xyz.openbmc_project.Inventory.Item.PowerSupply"};
23149c53ac9SJohnathan Mantey     auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp](
23249c53ac9SJohnathan Mantey                            const boost::system::error_code ec,
23349c53ac9SJohnathan Mantey                            const std::vector<std::string>& chassisPaths) {
23455c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassis respHandler enter";
2351abe55efSEd Tanous         if (ec)
2361abe55efSEd Tanous         {
23755c7b7a2SEd Tanous             BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec;
23849c53ac9SJohnathan Mantey             messages::internalError(sensorsAsyncResp->res);
23908777fb0SLewanczyk, Dawid             return;
24008777fb0SLewanczyk, Dawid         }
24108777fb0SLewanczyk, Dawid 
24249c53ac9SJohnathan Mantey         const std::string* chassisPath = nullptr;
24349c53ac9SJohnathan Mantey         std::string chassisName;
24449c53ac9SJohnathan Mantey         for (const std::string& chassis : chassisPaths)
2451abe55efSEd Tanous         {
24649c53ac9SJohnathan Mantey             std::size_t lastPos = chassis.rfind("/");
24749c53ac9SJohnathan Mantey             if (lastPos == std::string::npos)
2481abe55efSEd Tanous             {
24949c53ac9SJohnathan Mantey                 BMCWEB_LOG_ERROR << "Failed to find '/' in " << chassis;
250daf36e2eSEd Tanous                 continue;
251daf36e2eSEd Tanous             }
25249c53ac9SJohnathan Mantey             chassisName = chassis.substr(lastPos + 1);
25349c53ac9SJohnathan Mantey             if (chassisName == sensorsAsyncResp->chassisId)
2541abe55efSEd Tanous             {
25549c53ac9SJohnathan Mantey                 chassisPath = &chassis;
25649c53ac9SJohnathan Mantey                 break;
257daf36e2eSEd Tanous             }
25849c53ac9SJohnathan Mantey         }
25949c53ac9SJohnathan Mantey         if (chassisPath == nullptr)
2601abe55efSEd Tanous         {
26149c53ac9SJohnathan Mantey             messages::resourceNotFound(sensorsAsyncResp->res, "Chassis",
26249c53ac9SJohnathan Mantey                                        sensorsAsyncResp->chassisId);
26349c53ac9SJohnathan Mantey             return;
2641abe55efSEd Tanous         }
26508777fb0SLewanczyk, Dawid 
26649c53ac9SJohnathan Mantey         const std::string& chassisSubNode = sensorsAsyncResp->chassisSubNode;
26749c53ac9SJohnathan Mantey         if (chassisSubNode == "Power")
26849c53ac9SJohnathan Mantey         {
26949c53ac9SJohnathan Mantey             sensorsAsyncResp->res.jsonValue["@odata.type"] =
27049c53ac9SJohnathan Mantey                 "#Power.v1_5_2.Power";
27149c53ac9SJohnathan Mantey         }
27249c53ac9SJohnathan Mantey         else if (chassisSubNode == "Thermal")
27349c53ac9SJohnathan Mantey         {
27449c53ac9SJohnathan Mantey             sensorsAsyncResp->res.jsonValue["@odata.type"] =
27549c53ac9SJohnathan Mantey                 "#Thermal.v1_4_0.Thermal";
2764f9a2130SJennifer Lee             sensorsAsyncResp->res.jsonValue["Fans"] = nlohmann::json::array();
2774f9a2130SJennifer Lee             sensorsAsyncResp->res.jsonValue["Temperatures"] =
2784f9a2130SJennifer Lee                 nlohmann::json::array();
27949c53ac9SJohnathan Mantey         }
28049c53ac9SJohnathan Mantey         sensorsAsyncResp->res.jsonValue["@odata.id"] =
28149c53ac9SJohnathan Mantey             "/redfish/v1/Chassis/" + sensorsAsyncResp->chassisId + "/" +
28249c53ac9SJohnathan Mantey             chassisSubNode;
28349c53ac9SJohnathan Mantey 
28449c53ac9SJohnathan Mantey         sensorsAsyncResp->res.jsonValue["@odata.context"] =
28549c53ac9SJohnathan Mantey             "/redfish/v1/$metadata#" + chassisSubNode + "." + chassisSubNode;
28649c53ac9SJohnathan Mantey         sensorsAsyncResp->res.jsonValue["Id"] = chassisSubNode;
28749c53ac9SJohnathan Mantey         sensorsAsyncResp->res.jsonValue["Name"] = chassisSubNode;
28849c53ac9SJohnathan Mantey 
289*8fb49dd6SShawn McCarney         // Get the list of all sensors for this Chassis element
290*8fb49dd6SShawn McCarney         std::string sensorPath = *chassisPath + "/all_sensors";
29155c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
29249c53ac9SJohnathan Mantey             [sensorsAsyncResp, callback{std::move(callback)}](
29349c53ac9SJohnathan Mantey                 const boost::system::error_code ec,
29449c53ac9SJohnathan Mantey                 const std::variant<std::vector<std::string>>&
29549c53ac9SJohnathan Mantey                     variantEndpoints) {
29649c53ac9SJohnathan Mantey                 if (ec)
29749c53ac9SJohnathan Mantey                 {
29849c53ac9SJohnathan Mantey                     if (ec.value() != EBADR)
29949c53ac9SJohnathan Mantey                     {
30049c53ac9SJohnathan Mantey                         messages::internalError(sensorsAsyncResp->res);
30149c53ac9SJohnathan Mantey                         return;
30249c53ac9SJohnathan Mantey                     }
30349c53ac9SJohnathan Mantey                 }
30449c53ac9SJohnathan Mantey                 const std::vector<std::string>* nodeSensorList =
30549c53ac9SJohnathan Mantey                     std::get_if<std::vector<std::string>>(&(variantEndpoints));
30649c53ac9SJohnathan Mantey                 if (nodeSensorList == nullptr)
30749c53ac9SJohnathan Mantey                 {
30849c53ac9SJohnathan Mantey                     messages::resourceNotFound(
30949c53ac9SJohnathan Mantey                         sensorsAsyncResp->res, sensorsAsyncResp->chassisSubNode,
31049c53ac9SJohnathan Mantey                         sensorsAsyncResp->chassisSubNode == "Thermal"
31149c53ac9SJohnathan Mantey                             ? "Temperatures"
31249c53ac9SJohnathan Mantey                             : "Voltages");
31349c53ac9SJohnathan Mantey                     return;
31449c53ac9SJohnathan Mantey                 }
31549c53ac9SJohnathan Mantey                 const std::shared_ptr<boost::container::flat_set<std::string>>
31649c53ac9SJohnathan Mantey                     culledSensorList = std::make_shared<
31749c53ac9SJohnathan Mantey                         boost::container::flat_set<std::string>>();
31849c53ac9SJohnathan Mantey                 reduceSensorList(sensorsAsyncResp, nodeSensorList,
31949c53ac9SJohnathan Mantey                                  culledSensorList);
32049c53ac9SJohnathan Mantey                 callback(culledSensorList);
32149c53ac9SJohnathan Mantey             },
32249c53ac9SJohnathan Mantey             "xyz.openbmc_project.ObjectMapper", sensorPath,
32349c53ac9SJohnathan Mantey             "org.freedesktop.DBus.Properties", "Get",
32449c53ac9SJohnathan Mantey             "xyz.openbmc_project.Association", "endpoints");
32549c53ac9SJohnathan Mantey     };
32649c53ac9SJohnathan Mantey 
32749c53ac9SJohnathan Mantey     // Get the Chassis Collection
32849c53ac9SJohnathan Mantey     crow::connections::systemBus->async_method_call(
32949c53ac9SJohnathan Mantey         respHandler, "xyz.openbmc_project.ObjectMapper",
33049c53ac9SJohnathan Mantey         "/xyz/openbmc_project/object_mapper",
33149c53ac9SJohnathan Mantey         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
33249c53ac9SJohnathan Mantey         "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
33355c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis exit";
33408777fb0SLewanczyk, Dawid }
33508777fb0SLewanczyk, Dawid 
33608777fb0SLewanczyk, Dawid /**
337de629b6eSShawn McCarney  * @brief Finds all DBus object paths that implement ObjectManager.
338de629b6eSShawn McCarney  *
339de629b6eSShawn McCarney  * Creates a mapping from the associated connection name to the object path.
340de629b6eSShawn McCarney  *
341de629b6eSShawn McCarney  * Finds the object paths asynchronously.  Invokes callback when information has
342de629b6eSShawn McCarney  * been obtained.
343de629b6eSShawn McCarney  *
344de629b6eSShawn McCarney  * The callback must have the following signature:
345de629b6eSShawn McCarney  *   @code
346*8fb49dd6SShawn McCarney  *   callback(std::shared_ptr<boost::container::flat_map<std::string,
347*8fb49dd6SShawn McCarney  *                std::string>> objectMgrPaths)
348de629b6eSShawn McCarney  *   @endcode
349de629b6eSShawn McCarney  *
35049c53ac9SJohnathan Mantey  * @param sensorsAsyncResp Pointer to object holding response data.
351de629b6eSShawn McCarney  * @param callback Callback to invoke when object paths obtained.
352de629b6eSShawn McCarney  */
353de629b6eSShawn McCarney template <typename Callback>
354de629b6eSShawn McCarney void getObjectManagerPaths(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
355de629b6eSShawn McCarney                            Callback&& callback)
356de629b6eSShawn McCarney {
357de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getObjectManagerPaths enter";
358de629b6eSShawn McCarney     const std::array<std::string, 1> interfaces = {
359de629b6eSShawn McCarney         "org.freedesktop.DBus.ObjectManager"};
360de629b6eSShawn McCarney 
361de629b6eSShawn McCarney     // Response handler for GetSubTree DBus method
362de629b6eSShawn McCarney     auto respHandler = [callback{std::move(callback)},
363de629b6eSShawn McCarney                         SensorsAsyncResp](const boost::system::error_code ec,
364de629b6eSShawn McCarney                                           const GetSubTreeType& subtree) {
365de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler enter";
366de629b6eSShawn McCarney         if (ec)
367de629b6eSShawn McCarney         {
368de629b6eSShawn McCarney             messages::internalError(SensorsAsyncResp->res);
369de629b6eSShawn McCarney             BMCWEB_LOG_ERROR << "getObjectManagerPaths respHandler: DBus error "
370de629b6eSShawn McCarney                              << ec;
371de629b6eSShawn McCarney             return;
372de629b6eSShawn McCarney         }
373de629b6eSShawn McCarney 
374de629b6eSShawn McCarney         // Loop over returned object paths
375*8fb49dd6SShawn McCarney         std::shared_ptr<boost::container::flat_map<std::string, std::string>>
376*8fb49dd6SShawn McCarney             objectMgrPaths = std::make_shared<
377*8fb49dd6SShawn McCarney                 boost::container::flat_map<std::string, std::string>>();
378de629b6eSShawn McCarney         for (const std::pair<
379de629b6eSShawn McCarney                  std::string,
380de629b6eSShawn McCarney                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
381de629b6eSShawn McCarney                  object : subtree)
382de629b6eSShawn McCarney         {
383de629b6eSShawn McCarney             // Loop over connections for current object path
384de629b6eSShawn McCarney             const std::string& objectPath = object.first;
385de629b6eSShawn McCarney             for (const std::pair<std::string, std::vector<std::string>>&
386de629b6eSShawn McCarney                      objData : object.second)
387de629b6eSShawn McCarney             {
388de629b6eSShawn McCarney                 // Add mapping from connection to object path
389de629b6eSShawn McCarney                 const std::string& connection = objData.first;
390*8fb49dd6SShawn McCarney                 (*objectMgrPaths)[connection] = objectPath;
391de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "Added mapping " << connection << " -> "
392de629b6eSShawn McCarney                                  << objectPath;
393de629b6eSShawn McCarney             }
394de629b6eSShawn McCarney         }
395*8fb49dd6SShawn McCarney         callback(objectMgrPaths);
396de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler exit";
397de629b6eSShawn McCarney     };
398de629b6eSShawn McCarney 
399de629b6eSShawn McCarney     // Query mapper for all DBus object paths that implement ObjectManager
400de629b6eSShawn McCarney     crow::connections::systemBus->async_method_call(
401de629b6eSShawn McCarney         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
402de629b6eSShawn McCarney         "/xyz/openbmc_project/object_mapper",
403de629b6eSShawn McCarney         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
404de629b6eSShawn McCarney         interfaces);
405de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getObjectManagerPaths exit";
406de629b6eSShawn McCarney }
407de629b6eSShawn McCarney 
408de629b6eSShawn McCarney /**
40934dd179eSJames Feist  * @brief Retrieves the health from a sensor .
41034dd179eSJames Feist  * @param interfacesDict   Map of all sensor interfaces
41134dd179eSJames Feist  */
41234dd179eSJames Feist 
41334dd179eSJames Feist static std::string getHealth(
41434dd179eSJames Feist     const boost::container::flat_map<
41534dd179eSJames Feist         std::string, boost::container::flat_map<std::string, SensorVariant>>&
41634dd179eSJames Feist         interfacesDict)
41734dd179eSJames Feist {
41834dd179eSJames Feist     auto criticalThresholdIt =
41934dd179eSJames Feist         interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Critical");
42034dd179eSJames Feist     if (criticalThresholdIt != interfacesDict.end())
42134dd179eSJames Feist     {
42234dd179eSJames Feist         auto thresholdHighIt =
42334dd179eSJames Feist             criticalThresholdIt->second.find("CriticalAlarmHigh");
42434dd179eSJames Feist         auto thresholdLowIt =
42534dd179eSJames Feist             criticalThresholdIt->second.find("CriticalAlarmLow");
42634dd179eSJames Feist         if (thresholdHighIt != criticalThresholdIt->second.end())
42734dd179eSJames Feist         {
42834dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdHighIt->second);
42934dd179eSJames Feist             if (asserted == nullptr)
43034dd179eSJames Feist             {
43134dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
43234dd179eSJames Feist             }
43334dd179eSJames Feist             else if (*asserted)
43434dd179eSJames Feist             {
43534dd179eSJames Feist                 return "Critical";
43634dd179eSJames Feist             }
43734dd179eSJames Feist         }
43834dd179eSJames Feist         if (thresholdLowIt != criticalThresholdIt->second.end())
43934dd179eSJames Feist         {
44034dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdLowIt->second);
44134dd179eSJames Feist             if (asserted == nullptr)
44234dd179eSJames Feist             {
44334dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
44434dd179eSJames Feist             }
44534dd179eSJames Feist             else if (*asserted)
44634dd179eSJames Feist             {
44734dd179eSJames Feist                 return "Critical";
44834dd179eSJames Feist             }
44934dd179eSJames Feist         }
45034dd179eSJames Feist     }
45134dd179eSJames Feist 
45234dd179eSJames Feist     auto warningThresholdIt =
45334dd179eSJames Feist         interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Warning");
45434dd179eSJames Feist     if (warningThresholdIt != interfacesDict.end())
45534dd179eSJames Feist     {
45634dd179eSJames Feist         auto thresholdHighIt =
45734dd179eSJames Feist             warningThresholdIt->second.find("WarningAlarmHigh");
45834dd179eSJames Feist         auto thresholdLowIt =
45934dd179eSJames Feist             warningThresholdIt->second.find("WarningAlarmLow");
46034dd179eSJames Feist         if (thresholdHighIt != warningThresholdIt->second.end())
46134dd179eSJames Feist         {
46234dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdHighIt->second);
46334dd179eSJames Feist             if (asserted == nullptr)
46434dd179eSJames Feist             {
46534dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
46634dd179eSJames Feist             }
46734dd179eSJames Feist             else if (*asserted)
46834dd179eSJames Feist             {
46934dd179eSJames Feist                 return "Warning";
47034dd179eSJames Feist             }
47134dd179eSJames Feist         }
47234dd179eSJames Feist         if (thresholdLowIt != warningThresholdIt->second.end())
47334dd179eSJames Feist         {
47434dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdLowIt->second);
47534dd179eSJames Feist             if (asserted == nullptr)
47634dd179eSJames Feist             {
47734dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
47834dd179eSJames Feist             }
47934dd179eSJames Feist             else if (*asserted)
48034dd179eSJames Feist             {
48134dd179eSJames Feist                 return "Warning";
48234dd179eSJames Feist             }
48334dd179eSJames Feist         }
48434dd179eSJames Feist     }
48534dd179eSJames Feist     return "OK";
48634dd179eSJames Feist }
48734dd179eSJames Feist 
48834dd179eSJames Feist /**
48908777fb0SLewanczyk, Dawid  * @brief Builds a json sensor representation of a sensor.
49008777fb0SLewanczyk, Dawid  * @param sensorName  The name of the sensor to be built
491274fad5aSGunnar Mills  * @param sensorType  The type (temperature, fan_tach, etc) of the sensor to
49208777fb0SLewanczyk, Dawid  * build
49308777fb0SLewanczyk, Dawid  * @param interfacesDict  A dictionary of the interfaces and properties of said
49408777fb0SLewanczyk, Dawid  * interfaces to be built from
49508777fb0SLewanczyk, Dawid  * @param sensor_json  The json object to fill
49608777fb0SLewanczyk, Dawid  */
49708777fb0SLewanczyk, Dawid void objectInterfacesToJson(
49808777fb0SLewanczyk, Dawid     const std::string& sensorName, const std::string& sensorType,
49908777fb0SLewanczyk, Dawid     const boost::container::flat_map<
500aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>&
50108777fb0SLewanczyk, Dawid         interfacesDict,
5021abe55efSEd Tanous     nlohmann::json& sensor_json)
5031abe55efSEd Tanous {
50408777fb0SLewanczyk, Dawid     // We need a value interface before we can do anything with it
50555c7b7a2SEd Tanous     auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
5061abe55efSEd Tanous     if (valueIt == interfacesDict.end())
5071abe55efSEd Tanous     {
50855c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface";
50908777fb0SLewanczyk, Dawid         return;
51008777fb0SLewanczyk, Dawid     }
51108777fb0SLewanczyk, Dawid 
51208777fb0SLewanczyk, Dawid     // Assume values exist as is (10^0 == 1) if no scale exists
51308777fb0SLewanczyk, Dawid     int64_t scaleMultiplier = 0;
51408777fb0SLewanczyk, Dawid 
51555c7b7a2SEd Tanous     auto scaleIt = valueIt->second.find("Scale");
51608777fb0SLewanczyk, Dawid     // If a scale exists, pull value as int64, and use the scaling.
5171abe55efSEd Tanous     if (scaleIt != valueIt->second.end())
5181abe55efSEd Tanous     {
519abf2add6SEd Tanous         const int64_t* int64Value = std::get_if<int64_t>(&scaleIt->second);
5201abe55efSEd Tanous         if (int64Value != nullptr)
5211abe55efSEd Tanous         {
52208777fb0SLewanczyk, Dawid             scaleMultiplier = *int64Value;
52308777fb0SLewanczyk, Dawid         }
52408777fb0SLewanczyk, Dawid     }
52508777fb0SLewanczyk, Dawid 
52608777fb0SLewanczyk, Dawid     sensor_json["MemberId"] = sensorName;
527e742b6ccSEd Tanous     sensor_json["Name"] = boost::replace_all_copy(sensorName, "_", " ");
528e742b6ccSEd Tanous 
52908777fb0SLewanczyk, Dawid     sensor_json["Status"]["State"] = "Enabled";
53034dd179eSJames Feist     sensor_json["Status"]["Health"] = getHealth(interfacesDict);
53108777fb0SLewanczyk, Dawid 
53208777fb0SLewanczyk, Dawid     // Parameter to set to override the type we get from dbus, and force it to
53308777fb0SLewanczyk, Dawid     // int, regardless of what is available.  This is used for schemas like fan,
53408777fb0SLewanczyk, Dawid     // that require integers, not floats.
53508777fb0SLewanczyk, Dawid     bool forceToInt = false;
53608777fb0SLewanczyk, Dawid 
53708777fb0SLewanczyk, Dawid     const char* unit = "Reading";
5381abe55efSEd Tanous     if (sensorType == "temperature")
5391abe55efSEd Tanous     {
54008777fb0SLewanczyk, Dawid         unit = "ReadingCelsius";
5417885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature";
54208777fb0SLewanczyk, Dawid         // TODO(ed) Documentation says that path should be type fan_tach,
54308777fb0SLewanczyk, Dawid         // implementation seems to implement fan
5441abe55efSEd Tanous     }
5451abe55efSEd Tanous     else if (sensorType == "fan" || sensorType == "fan_tach")
5461abe55efSEd Tanous     {
54708777fb0SLewanczyk, Dawid         unit = "Reading";
54808777fb0SLewanczyk, Dawid         sensor_json["ReadingUnits"] = "RPM";
5497885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
55008777fb0SLewanczyk, Dawid         forceToInt = true;
5511abe55efSEd Tanous     }
5526f6d0d32SEd Tanous     else if (sensorType == "fan_pwm")
5536f6d0d32SEd Tanous     {
5546f6d0d32SEd Tanous         unit = "Reading";
5556f6d0d32SEd Tanous         sensor_json["ReadingUnits"] = "Percent";
5566f6d0d32SEd Tanous         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
5576f6d0d32SEd Tanous         forceToInt = true;
5586f6d0d32SEd Tanous     }
5591abe55efSEd Tanous     else if (sensorType == "voltage")
5601abe55efSEd Tanous     {
56108777fb0SLewanczyk, Dawid         unit = "ReadingVolts";
5627885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage";
5631abe55efSEd Tanous     }
5642474adfaSEd Tanous     else if (sensorType == "power")
5652474adfaSEd Tanous     {
56649c53ac9SJohnathan Mantey         std::string sensorNameLower =
56749c53ac9SJohnathan Mantey             boost::algorithm::to_lower_copy(sensorName);
56849c53ac9SJohnathan Mantey 
569028f7ebcSEddie James         if (!sensorName.compare("total_power"))
570028f7ebcSEddie James         {
571028f7ebcSEddie James             unit = "PowerConsumedWatts";
572028f7ebcSEddie James         }
573028f7ebcSEddie James         else if (sensorNameLower.find("input") != std::string::npos)
57449c53ac9SJohnathan Mantey         {
57549c53ac9SJohnathan Mantey             unit = "PowerInputWatts";
57649c53ac9SJohnathan Mantey         }
57749c53ac9SJohnathan Mantey         else
57849c53ac9SJohnathan Mantey         {
57949c53ac9SJohnathan Mantey             unit = "PowerOutputWatts";
58049c53ac9SJohnathan Mantey         }
5812474adfaSEd Tanous     }
5821abe55efSEd Tanous     else
5831abe55efSEd Tanous     {
58455c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
58508777fb0SLewanczyk, Dawid         return;
58608777fb0SLewanczyk, Dawid     }
58708777fb0SLewanczyk, Dawid     // Map of dbus interface name, dbus property name and redfish property_name
58808777fb0SLewanczyk, Dawid     std::vector<std::tuple<const char*, const char*, const char*>> properties;
58908777fb0SLewanczyk, Dawid     properties.reserve(7);
59008777fb0SLewanczyk, Dawid 
59108777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
592de629b6eSShawn McCarney 
593de629b6eSShawn McCarney     // If sensor type doesn't map to Redfish PowerSupply, add threshold props
594de629b6eSShawn McCarney     if ((sensorType != "current") && (sensorType != "power"))
595de629b6eSShawn McCarney     {
59608777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
59708777fb0SLewanczyk, Dawid                                 "WarningHigh", "UpperThresholdNonCritical");
59808777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
59908777fb0SLewanczyk, Dawid                                 "WarningLow", "LowerThresholdNonCritical");
60008777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
60108777fb0SLewanczyk, Dawid                                 "CriticalHigh", "UpperThresholdCritical");
60208777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
60308777fb0SLewanczyk, Dawid                                 "CriticalLow", "LowerThresholdCritical");
604de629b6eSShawn McCarney     }
60508777fb0SLewanczyk, Dawid 
6062474adfaSEd Tanous     // TODO Need to get UpperThresholdFatal and LowerThresholdFatal
6072474adfaSEd Tanous 
6081abe55efSEd Tanous     if (sensorType == "temperature")
6091abe55efSEd Tanous     {
61008777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
61108777fb0SLewanczyk, Dawid                                 "MinReadingRangeTemp");
61208777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
61308777fb0SLewanczyk, Dawid                                 "MaxReadingRangeTemp");
6141abe55efSEd Tanous     }
615de629b6eSShawn McCarney     else if ((sensorType != "current") && (sensorType != "power"))
6161abe55efSEd Tanous     {
617de629b6eSShawn McCarney         // Sensor type doesn't map to Redfish PowerSupply; add min/max props
61808777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
61908777fb0SLewanczyk, Dawid                                 "MinReadingRange");
62008777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
62108777fb0SLewanczyk, Dawid                                 "MaxReadingRange");
62208777fb0SLewanczyk, Dawid     }
62308777fb0SLewanczyk, Dawid 
62408777fb0SLewanczyk, Dawid     for (const std::tuple<const char*, const char*, const char*>& p :
6251abe55efSEd Tanous          properties)
6261abe55efSEd Tanous     {
62708777fb0SLewanczyk, Dawid         auto interfaceProperties = interfacesDict.find(std::get<0>(p));
6281abe55efSEd Tanous         if (interfaceProperties != interfacesDict.end())
6291abe55efSEd Tanous         {
630b01bf299SEd Tanous             auto valueIt = interfaceProperties->second.find(std::get<1>(p));
631b01bf299SEd Tanous             if (valueIt != interfaceProperties->second.end())
6321abe55efSEd Tanous             {
633b01bf299SEd Tanous                 const SensorVariant& valueVariant = valueIt->second;
634b01bf299SEd Tanous                 nlohmann::json& valueIt = sensor_json[std::get<2>(p)];
63508777fb0SLewanczyk, Dawid                 // Attempt to pull the int64 directly
636abf2add6SEd Tanous                 const int64_t* int64Value = std::get_if<int64_t>(&valueVariant);
63708777fb0SLewanczyk, Dawid 
638abf2add6SEd Tanous                 const double* doubleValue = std::get_if<double>(&valueVariant);
639028f7ebcSEddie James                 const uint32_t* uValue = std::get_if<uint32_t>(&valueVariant);
6406f6d0d32SEd Tanous                 double temp = 0.0;
6416f6d0d32SEd Tanous                 if (int64Value != nullptr)
6421abe55efSEd Tanous                 {
6436f6d0d32SEd Tanous                     temp = *int64Value;
6446f6d0d32SEd Tanous                 }
6456f6d0d32SEd Tanous                 else if (doubleValue != nullptr)
6461abe55efSEd Tanous                 {
6476f6d0d32SEd Tanous                     temp = *doubleValue;
6481abe55efSEd Tanous                 }
649028f7ebcSEddie James                 else if (uValue != nullptr)
650028f7ebcSEddie James                 {
651028f7ebcSEddie James                     temp = *uValue;
652028f7ebcSEddie James                 }
6531abe55efSEd Tanous                 else
6541abe55efSEd Tanous                 {
6556f6d0d32SEd Tanous                     BMCWEB_LOG_ERROR
6566f6d0d32SEd Tanous                         << "Got value interface that wasn't int or double";
6576f6d0d32SEd Tanous                     continue;
65808777fb0SLewanczyk, Dawid                 }
6596f6d0d32SEd Tanous                 temp = temp * std::pow(10, scaleMultiplier);
6606f6d0d32SEd Tanous                 if (forceToInt)
6616f6d0d32SEd Tanous                 {
662b01bf299SEd Tanous                     valueIt = static_cast<int64_t>(temp);
6636f6d0d32SEd Tanous                 }
6646f6d0d32SEd Tanous                 else
6656f6d0d32SEd Tanous                 {
666b01bf299SEd Tanous                     valueIt = temp;
66708777fb0SLewanczyk, Dawid                 }
66808777fb0SLewanczyk, Dawid             }
66908777fb0SLewanczyk, Dawid         }
67008777fb0SLewanczyk, Dawid     }
67155c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
67208777fb0SLewanczyk, Dawid }
67308777fb0SLewanczyk, Dawid 
6748bd25ccdSJames Feist static void
6758bd25ccdSJames Feist     populateFanRedundancy(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp)
6768bd25ccdSJames Feist {
6778bd25ccdSJames Feist     crow::connections::systemBus->async_method_call(
6788bd25ccdSJames Feist         [sensorsAsyncResp](const boost::system::error_code ec,
6798bd25ccdSJames Feist                            const GetSubTreeType& resp) {
6808bd25ccdSJames Feist             if (ec)
6818bd25ccdSJames Feist             {
6828bd25ccdSJames Feist                 return; // don't have to have this interface
6838bd25ccdSJames Feist             }
684e278c18fSEd Tanous             for (const std::pair<std::string,
685e278c18fSEd Tanous                                  std::vector<std::pair<
686e278c18fSEd Tanous                                      std::string, std::vector<std::string>>>>&
687e278c18fSEd Tanous                      pathPair : resp)
6888bd25ccdSJames Feist             {
689e278c18fSEd Tanous                 const std::string& path = pathPair.first;
690e278c18fSEd Tanous                 const std::vector<
691e278c18fSEd Tanous                     std::pair<std::string, std::vector<std::string>>>& objDict =
692e278c18fSEd Tanous                     pathPair.second;
6938bd25ccdSJames Feist                 if (objDict.empty())
6948bd25ccdSJames Feist                 {
6958bd25ccdSJames Feist                     continue; // this should be impossible
6968bd25ccdSJames Feist                 }
6978bd25ccdSJames Feist 
6988bd25ccdSJames Feist                 const std::string& owner = objDict.begin()->first;
6998bd25ccdSJames Feist                 crow::connections::systemBus->async_method_call(
7008bd25ccdSJames Feist                     [path, owner,
7018bd25ccdSJames Feist                      sensorsAsyncResp](const boost::system::error_code ec,
7028bd25ccdSJames Feist                                        std::variant<std::vector<std::string>>
7038bd25ccdSJames Feist                                            variantEndpoints) {
7048bd25ccdSJames Feist                         if (ec)
7058bd25ccdSJames Feist                         {
7068bd25ccdSJames Feist                             return; // if they don't have an association we
7078bd25ccdSJames Feist                                     // can't tell what chassis is
7088bd25ccdSJames Feist                         }
7098bd25ccdSJames Feist                         // verify part of the right chassis
7108bd25ccdSJames Feist                         auto endpoints = std::get_if<std::vector<std::string>>(
7118bd25ccdSJames Feist                             &variantEndpoints);
7128bd25ccdSJames Feist 
7138bd25ccdSJames Feist                         if (endpoints == nullptr)
7148bd25ccdSJames Feist                         {
7158bd25ccdSJames Feist                             BMCWEB_LOG_ERROR << "Invalid association interface";
7168bd25ccdSJames Feist                             messages::internalError(sensorsAsyncResp->res);
7178bd25ccdSJames Feist                             return;
7188bd25ccdSJames Feist                         }
7198bd25ccdSJames Feist 
7208bd25ccdSJames Feist                         auto found = std::find_if(
7218bd25ccdSJames Feist                             endpoints->begin(), endpoints->end(),
7228bd25ccdSJames Feist                             [sensorsAsyncResp](const std::string& entry) {
7238bd25ccdSJames Feist                                 return entry.find(
7248bd25ccdSJames Feist                                            sensorsAsyncResp->chassisId) !=
7258bd25ccdSJames Feist                                        std::string::npos;
7268bd25ccdSJames Feist                             });
7278bd25ccdSJames Feist 
7288bd25ccdSJames Feist                         if (found == endpoints->end())
7298bd25ccdSJames Feist                         {
7308bd25ccdSJames Feist                             return;
7318bd25ccdSJames Feist                         }
7328bd25ccdSJames Feist                         crow::connections::systemBus->async_method_call(
7338bd25ccdSJames Feist                             [path, sensorsAsyncResp](
7348bd25ccdSJames Feist                                 const boost::system::error_code ec,
7358bd25ccdSJames Feist                                 const boost::container::flat_map<
7368bd25ccdSJames Feist                                     std::string,
7378bd25ccdSJames Feist                                     std::variant<uint8_t,
7388bd25ccdSJames Feist                                                  std::vector<std::string>,
7398bd25ccdSJames Feist                                                  std::string>>& ret) {
7408bd25ccdSJames Feist                                 if (ec)
7418bd25ccdSJames Feist                                 {
7428bd25ccdSJames Feist                                     return; // don't have to have this
7438bd25ccdSJames Feist                                             // interface
7448bd25ccdSJames Feist                                 }
7458bd25ccdSJames Feist                                 auto findFailures = ret.find("AllowedFailures");
7468bd25ccdSJames Feist                                 auto findCollection = ret.find("Collection");
7478bd25ccdSJames Feist                                 auto findStatus = ret.find("Status");
7488bd25ccdSJames Feist 
7498bd25ccdSJames Feist                                 if (findFailures == ret.end() ||
7508bd25ccdSJames Feist                                     findCollection == ret.end() ||
7518bd25ccdSJames Feist                                     findStatus == ret.end())
7528bd25ccdSJames Feist                                 {
7538bd25ccdSJames Feist                                     BMCWEB_LOG_ERROR
7548bd25ccdSJames Feist                                         << "Invalid redundancy interface";
7558bd25ccdSJames Feist                                     messages::internalError(
7568bd25ccdSJames Feist                                         sensorsAsyncResp->res);
7578bd25ccdSJames Feist                                     return;
7588bd25ccdSJames Feist                                 }
7598bd25ccdSJames Feist 
7608bd25ccdSJames Feist                                 auto allowedFailures = std::get_if<uint8_t>(
7618bd25ccdSJames Feist                                     &(findFailures->second));
7628bd25ccdSJames Feist                                 auto collection =
7638bd25ccdSJames Feist                                     std::get_if<std::vector<std::string>>(
7648bd25ccdSJames Feist                                         &(findCollection->second));
7658bd25ccdSJames Feist                                 auto status = std::get_if<std::string>(
7668bd25ccdSJames Feist                                     &(findStatus->second));
7678bd25ccdSJames Feist 
7688bd25ccdSJames Feist                                 if (allowedFailures == nullptr ||
7698bd25ccdSJames Feist                                     collection == nullptr || status == nullptr)
7708bd25ccdSJames Feist                                 {
7718bd25ccdSJames Feist 
7728bd25ccdSJames Feist                                     BMCWEB_LOG_ERROR
7738bd25ccdSJames Feist                                         << "Invalid redundancy interface "
7748bd25ccdSJames Feist                                            "types";
7758bd25ccdSJames Feist                                     messages::internalError(
7768bd25ccdSJames Feist                                         sensorsAsyncResp->res);
7778bd25ccdSJames Feist                                     return;
7788bd25ccdSJames Feist                                 }
7798bd25ccdSJames Feist                                 size_t lastSlash = path.rfind("/");
7808bd25ccdSJames Feist                                 if (lastSlash == std::string::npos)
7818bd25ccdSJames Feist                                 {
7828bd25ccdSJames Feist                                     // this should be impossible
7838bd25ccdSJames Feist                                     messages::internalError(
7848bd25ccdSJames Feist                                         sensorsAsyncResp->res);
7858bd25ccdSJames Feist                                     return;
7868bd25ccdSJames Feist                                 }
7878bd25ccdSJames Feist                                 std::string name = path.substr(lastSlash + 1);
7888bd25ccdSJames Feist                                 std::replace(name.begin(), name.end(), '_',
7898bd25ccdSJames Feist                                              ' ');
7908bd25ccdSJames Feist 
7918bd25ccdSJames Feist                                 std::string health;
7928bd25ccdSJames Feist 
7938bd25ccdSJames Feist                                 if (boost::ends_with(*status, "Full"))
7948bd25ccdSJames Feist                                 {
7958bd25ccdSJames Feist                                     health = "OK";
7968bd25ccdSJames Feist                                 }
7978bd25ccdSJames Feist                                 else if (boost::ends_with(*status, "Degraded"))
7988bd25ccdSJames Feist                                 {
7998bd25ccdSJames Feist                                     health = "Warning";
8008bd25ccdSJames Feist                                 }
8018bd25ccdSJames Feist                                 else
8028bd25ccdSJames Feist                                 {
8038bd25ccdSJames Feist                                     health = "Critical";
8048bd25ccdSJames Feist                                 }
8058bd25ccdSJames Feist                                 std::vector<nlohmann::json> redfishCollection;
8068bd25ccdSJames Feist                                 const auto& fanRedfish =
8078bd25ccdSJames Feist                                     sensorsAsyncResp->res.jsonValue["Fans"];
8088bd25ccdSJames Feist                                 for (const std::string& item : *collection)
8098bd25ccdSJames Feist                                 {
8108bd25ccdSJames Feist                                     lastSlash = item.rfind("/");
8118bd25ccdSJames Feist                                     // make a copy as collection is const
8128bd25ccdSJames Feist                                     std::string itemName =
8138bd25ccdSJames Feist                                         item.substr(lastSlash + 1);
8148bd25ccdSJames Feist                                     /*
8158bd25ccdSJames Feist                                     todo(ed): merge patch that fixes the names
8168bd25ccdSJames Feist                                     std::replace(itemName.begin(),
8178bd25ccdSJames Feist                                                  itemName.end(), '_', ' ');*/
8188bd25ccdSJames Feist                                     auto schemaItem = std::find_if(
8198bd25ccdSJames Feist                                         fanRedfish.begin(), fanRedfish.end(),
8208bd25ccdSJames Feist                                         [itemName](const nlohmann::json& fan) {
8218bd25ccdSJames Feist                                             return fan["MemberId"] == itemName;
8228bd25ccdSJames Feist                                         });
8238bd25ccdSJames Feist                                     if (schemaItem != fanRedfish.end())
8248bd25ccdSJames Feist                                     {
8258bd25ccdSJames Feist                                         redfishCollection.push_back(
8268bd25ccdSJames Feist                                             {{"@odata.id",
8278bd25ccdSJames Feist                                               (*schemaItem)["@odata.id"]}});
8288bd25ccdSJames Feist                                     }
8298bd25ccdSJames Feist                                     else
8308bd25ccdSJames Feist                                     {
8318bd25ccdSJames Feist                                         BMCWEB_LOG_ERROR
8328bd25ccdSJames Feist                                             << "failed to find fan in schema";
8338bd25ccdSJames Feist                                         messages::internalError(
8348bd25ccdSJames Feist                                             sensorsAsyncResp->res);
8358bd25ccdSJames Feist                                         return;
8368bd25ccdSJames Feist                                     }
8378bd25ccdSJames Feist                                 }
8388bd25ccdSJames Feist 
8398bd25ccdSJames Feist                                 auto& resp = sensorsAsyncResp->res
8408bd25ccdSJames Feist                                                  .jsonValue["Redundancy"];
8418bd25ccdSJames Feist                                 resp.push_back(
8428bd25ccdSJames Feist                                     {{"@odata.id",
8438bd25ccdSJames Feist                                       "/refish/v1/Chassis/" +
8448bd25ccdSJames Feist                                           sensorsAsyncResp->chassisId + "/" +
8458bd25ccdSJames Feist                                           sensorsAsyncResp->chassisSubNode +
8468bd25ccdSJames Feist                                           "#/Redundancy/" +
8478bd25ccdSJames Feist                                           std::to_string(resp.size())},
8488bd25ccdSJames Feist                                      {"@odata.type",
8498bd25ccdSJames Feist                                       "#Redundancy.v1_3_2.Redundancy"},
8508bd25ccdSJames Feist                                      {"MinNumNeeded",
8518bd25ccdSJames Feist                                       collection->size() - *allowedFailures},
8528bd25ccdSJames Feist                                      {"MemberId", name},
8538bd25ccdSJames Feist                                      {"Mode", "N+m"},
8548bd25ccdSJames Feist                                      {"Name", name},
8558bd25ccdSJames Feist                                      {"RedundancySet", redfishCollection},
8568bd25ccdSJames Feist                                      {"Status",
8578bd25ccdSJames Feist                                       {{"Health", health},
8588bd25ccdSJames Feist                                        {"State", "Enabled"}}}});
8598bd25ccdSJames Feist                             },
8608bd25ccdSJames Feist                             owner, path, "org.freedesktop.DBus.Properties",
8618bd25ccdSJames Feist                             "GetAll",
8628bd25ccdSJames Feist                             "xyz.openbmc_project.Control.FanRedundancy");
8638bd25ccdSJames Feist                     },
8648bd25ccdSJames Feist                     "xyz.openbmc_project.ObjectMapper", path + "/inventory",
8658bd25ccdSJames Feist                     "org.freedesktop.DBus.Properties", "Get",
8668bd25ccdSJames Feist                     "xyz.openbmc_project.Association", "endpoints");
8678bd25ccdSJames Feist             }
8688bd25ccdSJames Feist         },
8698bd25ccdSJames Feist         "xyz.openbmc_project.ObjectMapper",
8708bd25ccdSJames Feist         "/xyz/openbmc_project/object_mapper",
8718bd25ccdSJames Feist         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
8728bd25ccdSJames Feist         "/xyz/openbmc_project/control", 2,
8738bd25ccdSJames Feist         std::array<const char*, 1>{
8748bd25ccdSJames Feist             "xyz.openbmc_project.Control.FanRedundancy"});
8758bd25ccdSJames Feist }
8768bd25ccdSJames Feist 
87749c53ac9SJohnathan Mantey void sortJSONResponse(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
87849c53ac9SJohnathan Mantey {
87949c53ac9SJohnathan Mantey     nlohmann::json& response = SensorsAsyncResp->res.jsonValue;
88049c53ac9SJohnathan Mantey     std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
88149c53ac9SJohnathan Mantey     if (SensorsAsyncResp->chassisSubNode == "Power")
88249c53ac9SJohnathan Mantey     {
88349c53ac9SJohnathan Mantey         sensorHeaders = {"Voltages", "PowerSupplies"};
88449c53ac9SJohnathan Mantey     }
88549c53ac9SJohnathan Mantey     for (const std::string& sensorGroup : sensorHeaders)
88649c53ac9SJohnathan Mantey     {
88749c53ac9SJohnathan Mantey         nlohmann::json::iterator entry = response.find(sensorGroup);
88849c53ac9SJohnathan Mantey         if (entry != response.end())
88949c53ac9SJohnathan Mantey         {
89049c53ac9SJohnathan Mantey             std::sort(entry->begin(), entry->end(),
89149c53ac9SJohnathan Mantey                       [](nlohmann::json& c1, nlohmann::json& c2) {
89249c53ac9SJohnathan Mantey                           return c1["Name"] < c2["Name"];
89349c53ac9SJohnathan Mantey                       });
89449c53ac9SJohnathan Mantey 
89549c53ac9SJohnathan Mantey             // add the index counts to the end of each entry
89649c53ac9SJohnathan Mantey             size_t count = 0;
89749c53ac9SJohnathan Mantey             for (nlohmann::json& sensorJson : *entry)
89849c53ac9SJohnathan Mantey             {
89949c53ac9SJohnathan Mantey                 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
90049c53ac9SJohnathan Mantey                 if (odata == sensorJson.end())
90149c53ac9SJohnathan Mantey                 {
90249c53ac9SJohnathan Mantey                     continue;
90349c53ac9SJohnathan Mantey                 }
90449c53ac9SJohnathan Mantey                 std::string* value = odata->get_ptr<std::string*>();
90549c53ac9SJohnathan Mantey                 if (value != nullptr)
90649c53ac9SJohnathan Mantey                 {
90749c53ac9SJohnathan Mantey                     *value += std::to_string(count);
90849c53ac9SJohnathan Mantey                     count++;
90949c53ac9SJohnathan Mantey                 }
91049c53ac9SJohnathan Mantey             }
91149c53ac9SJohnathan Mantey         }
91249c53ac9SJohnathan Mantey     }
91349c53ac9SJohnathan Mantey }
91449c53ac9SJohnathan Mantey 
91508777fb0SLewanczyk, Dawid /**
916*8fb49dd6SShawn McCarney  * @brief Finds the JSON object for the specified sensor.
917*8fb49dd6SShawn McCarney  *
918*8fb49dd6SShawn McCarney  * Searches the JSON response in sensorsAsyncResp for an object corresponding to
919*8fb49dd6SShawn McCarney  * the specified sensor.
920*8fb49dd6SShawn McCarney  *
921*8fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
922*8fb49dd6SShawn McCarney  * @param sensorName DBus object path to the sensor.
923*8fb49dd6SShawn McCarney  * @return Pointer to JSON object, or nullptr if object not found.
924*8fb49dd6SShawn McCarney  */
925*8fb49dd6SShawn McCarney static nlohmann::json*
926*8fb49dd6SShawn McCarney     findSensorJson(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
927*8fb49dd6SShawn McCarney                    const std::string& sensorName)
928*8fb49dd6SShawn McCarney {
929*8fb49dd6SShawn McCarney     // Get base name of sensor
930*8fb49dd6SShawn McCarney     std::size_t lastSlash = sensorName.rfind('/');
931*8fb49dd6SShawn McCarney     if (lastSlash != std::string::npos)
932*8fb49dd6SShawn McCarney     {
933*8fb49dd6SShawn McCarney         std::string baseSensorName = sensorName.substr(lastSlash + 1);
934*8fb49dd6SShawn McCarney 
935*8fb49dd6SShawn McCarney         // Loop through JSON sensor groups that could contain sensor
936*8fb49dd6SShawn McCarney         nlohmann::json& response = sensorsAsyncResp->res.jsonValue;
937*8fb49dd6SShawn McCarney         std::array<std::string, 4> sensorGroups{"Temperatures", "Fans",
938*8fb49dd6SShawn McCarney                                                 "Voltages", "PowerSupplies"};
939*8fb49dd6SShawn McCarney         for (const std::string& sensorGroup : sensorGroups)
940*8fb49dd6SShawn McCarney         {
941*8fb49dd6SShawn McCarney             nlohmann::json::iterator groupIt = response.find(sensorGroup);
942*8fb49dd6SShawn McCarney             if (groupIt != response.end())
943*8fb49dd6SShawn McCarney             {
944*8fb49dd6SShawn McCarney                 // Loop through sensors in current group
945*8fb49dd6SShawn McCarney                 for (nlohmann::json& sensorJson : *groupIt)
946*8fb49dd6SShawn McCarney                 {
947*8fb49dd6SShawn McCarney                     // Check if this is the sensor we are looking for
948*8fb49dd6SShawn McCarney                     nlohmann::json::iterator memberIdIt =
949*8fb49dd6SShawn McCarney                         sensorJson.find("MemberId");
950*8fb49dd6SShawn McCarney                     if (memberIdIt != sensorJson.end())
951*8fb49dd6SShawn McCarney                     {
952*8fb49dd6SShawn McCarney                         std::string* memberId =
953*8fb49dd6SShawn McCarney                             memberIdIt->get_ptr<std::string*>();
954*8fb49dd6SShawn McCarney                         if ((memberId != nullptr) &&
955*8fb49dd6SShawn McCarney                             (*memberId == baseSensorName))
956*8fb49dd6SShawn McCarney                         {
957*8fb49dd6SShawn McCarney                             return &sensorJson;
958*8fb49dd6SShawn McCarney                         }
959*8fb49dd6SShawn McCarney                     }
960*8fb49dd6SShawn McCarney                 }
961*8fb49dd6SShawn McCarney             }
962*8fb49dd6SShawn McCarney         }
963*8fb49dd6SShawn McCarney     }
964*8fb49dd6SShawn McCarney 
965*8fb49dd6SShawn McCarney     // Unable to find JSON object for specified sensor
966*8fb49dd6SShawn McCarney     return nullptr;
967*8fb49dd6SShawn McCarney }
968*8fb49dd6SShawn McCarney 
969*8fb49dd6SShawn McCarney /**
970*8fb49dd6SShawn McCarney  * @brief Updates sensor status in JSON response based on inventory item status.
971*8fb49dd6SShawn McCarney  *
972*8fb49dd6SShawn McCarney  * Updates the status of the specified sensor based on the status of a related
973*8fb49dd6SShawn McCarney  * inventory item.
974*8fb49dd6SShawn McCarney  *
975*8fb49dd6SShawn McCarney  * Modifies the Redfish Status property in the JSON response if the inventory
976*8fb49dd6SShawn McCarney  * item indicates the hardware is not present or not functional.
977*8fb49dd6SShawn McCarney  *
978*8fb49dd6SShawn McCarney  * The D-Bus Present and Functional properties are typically on the inventory
979*8fb49dd6SShawn McCarney  * item rather than the sensor.
980*8fb49dd6SShawn McCarney  *
981*8fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
982*8fb49dd6SShawn McCarney  * @param sensorName DBus object path to the sensor.
983*8fb49dd6SShawn McCarney  * @param interfacesDict Map containing the interfaces and properties of the
984*8fb49dd6SShawn McCarney  * inventory item associated with this sensor.
985*8fb49dd6SShawn McCarney  */
986*8fb49dd6SShawn McCarney static void updateSensorStatus(
987*8fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
988*8fb49dd6SShawn McCarney     const std::string& sensorName,
989*8fb49dd6SShawn McCarney     const boost::container::flat_map<
990*8fb49dd6SShawn McCarney         std::string, boost::container::flat_map<std::string, SensorVariant>>&
991*8fb49dd6SShawn McCarney         interfacesDict)
992*8fb49dd6SShawn McCarney {
993*8fb49dd6SShawn McCarney     // Find the JSON object in the response for this sensor
994*8fb49dd6SShawn McCarney     nlohmann::json* sensorJson = findSensorJson(sensorsAsyncResp, sensorName);
995*8fb49dd6SShawn McCarney     if (sensorJson != nullptr)
996*8fb49dd6SShawn McCarney     {
997*8fb49dd6SShawn McCarney         // Get Inventory.Item.Present property of inventory item
998*8fb49dd6SShawn McCarney         auto itemIt = interfacesDict.find("xyz.openbmc_project.Inventory.Item");
999*8fb49dd6SShawn McCarney         if (itemIt != interfacesDict.end())
1000*8fb49dd6SShawn McCarney         {
1001*8fb49dd6SShawn McCarney             auto presentIt = itemIt->second.find("Present");
1002*8fb49dd6SShawn McCarney             if (presentIt != itemIt->second.end())
1003*8fb49dd6SShawn McCarney             {
1004*8fb49dd6SShawn McCarney                 const bool* present = std::get_if<bool>(&presentIt->second);
1005*8fb49dd6SShawn McCarney                 if ((present != nullptr) && (*present == false))
1006*8fb49dd6SShawn McCarney                 {
1007*8fb49dd6SShawn McCarney                     // Inventory item is not present; update sensor State
1008*8fb49dd6SShawn McCarney                     (*sensorJson)["Status"]["State"] = "Absent";
1009*8fb49dd6SShawn McCarney                 }
1010*8fb49dd6SShawn McCarney             }
1011*8fb49dd6SShawn McCarney         }
1012*8fb49dd6SShawn McCarney 
1013*8fb49dd6SShawn McCarney         // Get OperationalStatus.Functional property of inventory item
1014*8fb49dd6SShawn McCarney         auto opStatusIt = interfacesDict.find(
1015*8fb49dd6SShawn McCarney             "xyz.openbmc_project.State.Decorator.OperationalStatus");
1016*8fb49dd6SShawn McCarney         if (opStatusIt != interfacesDict.end())
1017*8fb49dd6SShawn McCarney         {
1018*8fb49dd6SShawn McCarney             auto functionalIt = opStatusIt->second.find("Functional");
1019*8fb49dd6SShawn McCarney             if (functionalIt != opStatusIt->second.end())
1020*8fb49dd6SShawn McCarney             {
1021*8fb49dd6SShawn McCarney                 const bool* functional =
1022*8fb49dd6SShawn McCarney                     std::get_if<bool>(&functionalIt->second);
1023*8fb49dd6SShawn McCarney                 if ((functional != nullptr) && (*functional == false))
1024*8fb49dd6SShawn McCarney                 {
1025*8fb49dd6SShawn McCarney                     // Inventory item is not functional; update sensor Health
1026*8fb49dd6SShawn McCarney                     (*sensorJson)["Status"]["Health"] = "Critical";
1027*8fb49dd6SShawn McCarney                 }
1028*8fb49dd6SShawn McCarney             }
1029*8fb49dd6SShawn McCarney         }
1030*8fb49dd6SShawn McCarney     }
1031*8fb49dd6SShawn McCarney }
1032*8fb49dd6SShawn McCarney 
1033*8fb49dd6SShawn McCarney /**
1034*8fb49dd6SShawn McCarney  * @brief Gets status of inventory items associated with sensors.
1035*8fb49dd6SShawn McCarney  *
1036*8fb49dd6SShawn McCarney  * Gets the D-Bus status properties for the inventory items associated with
1037*8fb49dd6SShawn McCarney  * sensors.
1038*8fb49dd6SShawn McCarney  *
1039*8fb49dd6SShawn McCarney  * Updates the Redfish sensors status in the JSON response, if needed, based on
1040*8fb49dd6SShawn McCarney  * the inventory items status.
1041*8fb49dd6SShawn McCarney  *
1042*8fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
1043*8fb49dd6SShawn McCarney  * @param sensorToInvMap Mappings from sensor object path to the associated
1044*8fb49dd6SShawn McCarney  * inventory object path.
1045*8fb49dd6SShawn McCarney  * @param invConnections Connections that provide the status
1046*8fb49dd6SShawn McCarney  * interfaces/properties for the inventory items.
1047*8fb49dd6SShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
1048*8fb49dd6SShawn McCarney  * implements ObjectManager.
1049*8fb49dd6SShawn McCarney  */
1050*8fb49dd6SShawn McCarney static void getInventoryItemsStatus(
1051*8fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1052*8fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1053*8fb49dd6SShawn McCarney         sensorToInvMap,
1054*8fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_set<std::string>> invConnections,
1055*8fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1056*8fb49dd6SShawn McCarney         objectMgrPaths)
1057*8fb49dd6SShawn McCarney {
1058*8fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsStatus enter";
1059*8fb49dd6SShawn McCarney 
1060*8fb49dd6SShawn McCarney     // Loop through all connections providing inventory item status
1061*8fb49dd6SShawn McCarney     for (const std::string& invConnection : *invConnections)
1062*8fb49dd6SShawn McCarney     {
1063*8fb49dd6SShawn McCarney         // Response handler for GetManagedObjects
1064*8fb49dd6SShawn McCarney         auto respHandler = [sensorsAsyncResp,
1065*8fb49dd6SShawn McCarney                             sensorToInvMap](const boost::system::error_code ec,
1066*8fb49dd6SShawn McCarney                                             ManagedObjectsVectorType& resp) {
1067*8fb49dd6SShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemsStatus respHandler enter";
1068*8fb49dd6SShawn McCarney             if (ec)
1069*8fb49dd6SShawn McCarney             {
1070*8fb49dd6SShawn McCarney                 BMCWEB_LOG_ERROR
1071*8fb49dd6SShawn McCarney                     << "getInventoryItemsStatus respHandler DBus error " << ec;
1072*8fb49dd6SShawn McCarney                 messages::internalError(sensorsAsyncResp->res);
1073*8fb49dd6SShawn McCarney                 return;
1074*8fb49dd6SShawn McCarney             }
1075*8fb49dd6SShawn McCarney 
1076*8fb49dd6SShawn McCarney             // Loop through returned object paths
1077*8fb49dd6SShawn McCarney             for (const auto& objDictEntry : resp)
1078*8fb49dd6SShawn McCarney             {
1079*8fb49dd6SShawn McCarney                 const std::string& objPath =
1080*8fb49dd6SShawn McCarney                     static_cast<const std::string&>(objDictEntry.first);
1081*8fb49dd6SShawn McCarney 
1082*8fb49dd6SShawn McCarney                 // Find all sensors associated with this inventory item
1083*8fb49dd6SShawn McCarney                 for (const std::pair<std::string, std::string>& pair :
1084*8fb49dd6SShawn McCarney                      *sensorToInvMap)
1085*8fb49dd6SShawn McCarney                 {
1086*8fb49dd6SShawn McCarney                     if (pair.second == objPath)
1087*8fb49dd6SShawn McCarney                     {
1088*8fb49dd6SShawn McCarney                         // Update sensor status based on inventory item status
1089*8fb49dd6SShawn McCarney                         updateSensorStatus(sensorsAsyncResp, pair.first,
1090*8fb49dd6SShawn McCarney                                            objDictEntry.second);
1091*8fb49dd6SShawn McCarney                     }
1092*8fb49dd6SShawn McCarney                 }
1093*8fb49dd6SShawn McCarney             }
1094*8fb49dd6SShawn McCarney 
1095*8fb49dd6SShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemsStatus respHandler exit";
1096*8fb49dd6SShawn McCarney         };
1097*8fb49dd6SShawn McCarney 
1098*8fb49dd6SShawn McCarney         // Find DBus object path that implements ObjectManager for the current
1099*8fb49dd6SShawn McCarney         // connection.  If no mapping found, default to "/".
1100*8fb49dd6SShawn McCarney         auto iter = objectMgrPaths->find(invConnection);
1101*8fb49dd6SShawn McCarney         const std::string& objectMgrPath =
1102*8fb49dd6SShawn McCarney             (iter != objectMgrPaths->end()) ? iter->second : "/";
1103*8fb49dd6SShawn McCarney         BMCWEB_LOG_DEBUG << "ObjectManager path for " << invConnection << " is "
1104*8fb49dd6SShawn McCarney                          << objectMgrPath;
1105*8fb49dd6SShawn McCarney 
1106*8fb49dd6SShawn McCarney         // Get all object paths and their interfaces for current connection
1107*8fb49dd6SShawn McCarney         crow::connections::systemBus->async_method_call(
1108*8fb49dd6SShawn McCarney             std::move(respHandler), invConnection, objectMgrPath,
1109*8fb49dd6SShawn McCarney             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1110*8fb49dd6SShawn McCarney     }
1111*8fb49dd6SShawn McCarney 
1112*8fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsStatus exit";
1113*8fb49dd6SShawn McCarney }
1114*8fb49dd6SShawn McCarney 
1115*8fb49dd6SShawn McCarney /**
1116*8fb49dd6SShawn McCarney  * @brief Gets connections that provide status information on inventory items.
1117*8fb49dd6SShawn McCarney  *
1118*8fb49dd6SShawn McCarney  * Gets the D-Bus connections (services) that provide the interfaces and
1119*8fb49dd6SShawn McCarney  * properties containing status information for the inventory items.
1120*8fb49dd6SShawn McCarney  *
1121*8fb49dd6SShawn McCarney  * Finds the connections asynchronously.  Invokes callback when information has
1122*8fb49dd6SShawn McCarney  * been obtained.
1123*8fb49dd6SShawn McCarney  *
1124*8fb49dd6SShawn McCarney  * The callback must have the following signature:
1125*8fb49dd6SShawn McCarney  *   @code
1126*8fb49dd6SShawn McCarney  *   callback(std::shared_ptr<boost::container::flat_set<std::string>>
1127*8fb49dd6SShawn McCarney  *            invConnections)
1128*8fb49dd6SShawn McCarney  *   @endcode
1129*8fb49dd6SShawn McCarney  *
1130*8fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
1131*8fb49dd6SShawn McCarney  * @param sensorToInvMap Mappings from sensor object path to the associated
1132*8fb49dd6SShawn McCarney  * inventory object path.
1133*8fb49dd6SShawn McCarney  * @param callback Callback to invoke when connections have been obtained.
1134*8fb49dd6SShawn McCarney  */
1135*8fb49dd6SShawn McCarney template <typename Callback>
1136*8fb49dd6SShawn McCarney static void getInventoryItemsConnections(
1137*8fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1138*8fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1139*8fb49dd6SShawn McCarney         sensorToInvMap,
1140*8fb49dd6SShawn McCarney     Callback&& callback)
1141*8fb49dd6SShawn McCarney {
1142*8fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsConnections enter";
1143*8fb49dd6SShawn McCarney 
1144*8fb49dd6SShawn McCarney     const std::string path = "/xyz/openbmc_project/inventory";
1145*8fb49dd6SShawn McCarney     const std::array<std::string, 2> interfaces = {
1146*8fb49dd6SShawn McCarney         "xyz.openbmc_project.Inventory.Item",
1147*8fb49dd6SShawn McCarney         "xyz.openbmc_project.State.Decorator.OperationalStatus"};
1148*8fb49dd6SShawn McCarney 
1149*8fb49dd6SShawn McCarney     // Response handler for parsing output from GetSubTree
1150*8fb49dd6SShawn McCarney     auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
1151*8fb49dd6SShawn McCarney                         sensorToInvMap](const boost::system::error_code ec,
1152*8fb49dd6SShawn McCarney                                         const GetSubTreeType& subtree) {
1153*8fb49dd6SShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler enter";
1154*8fb49dd6SShawn McCarney         if (ec)
1155*8fb49dd6SShawn McCarney         {
1156*8fb49dd6SShawn McCarney             messages::internalError(sensorsAsyncResp->res);
1157*8fb49dd6SShawn McCarney             BMCWEB_LOG_ERROR
1158*8fb49dd6SShawn McCarney                 << "getInventoryItemsConnections respHandler DBus error " << ec;
1159*8fb49dd6SShawn McCarney             return;
1160*8fb49dd6SShawn McCarney         }
1161*8fb49dd6SShawn McCarney 
1162*8fb49dd6SShawn McCarney         // Make unique list of connections for desired inventory items
1163*8fb49dd6SShawn McCarney         std::shared_ptr<boost::container::flat_set<std::string>>
1164*8fb49dd6SShawn McCarney             invConnections =
1165*8fb49dd6SShawn McCarney                 std::make_shared<boost::container::flat_set<std::string>>();
1166*8fb49dd6SShawn McCarney         invConnections->reserve(8);
1167*8fb49dd6SShawn McCarney 
1168*8fb49dd6SShawn McCarney         // Loop through objects from GetSubTree
1169*8fb49dd6SShawn McCarney         for (const std::pair<
1170*8fb49dd6SShawn McCarney                  std::string,
1171*8fb49dd6SShawn McCarney                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
1172*8fb49dd6SShawn McCarney                  object : subtree)
1173*8fb49dd6SShawn McCarney         {
1174*8fb49dd6SShawn McCarney             // Look for inventory item object path in the sensor->inventory map
1175*8fb49dd6SShawn McCarney             const std::string& objPath = object.first;
1176*8fb49dd6SShawn McCarney             for (const std::pair<std::string, std::string>& pair :
1177*8fb49dd6SShawn McCarney                  *sensorToInvMap)
1178*8fb49dd6SShawn McCarney             {
1179*8fb49dd6SShawn McCarney                 if (pair.second == objPath)
1180*8fb49dd6SShawn McCarney                 {
1181*8fb49dd6SShawn McCarney                     // Store all connections to inventory item
1182*8fb49dd6SShawn McCarney                     for (const std::pair<std::string, std::vector<std::string>>&
1183*8fb49dd6SShawn McCarney                              objData : object.second)
1184*8fb49dd6SShawn McCarney                     {
1185*8fb49dd6SShawn McCarney                         const std::string& invConnection = objData.first;
1186*8fb49dd6SShawn McCarney                         invConnections->insert(invConnection);
1187*8fb49dd6SShawn McCarney                     }
1188*8fb49dd6SShawn McCarney                     break;
1189*8fb49dd6SShawn McCarney                 }
1190*8fb49dd6SShawn McCarney             }
1191*8fb49dd6SShawn McCarney         }
1192*8fb49dd6SShawn McCarney         callback(invConnections);
1193*8fb49dd6SShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler exit";
1194*8fb49dd6SShawn McCarney     };
1195*8fb49dd6SShawn McCarney 
1196*8fb49dd6SShawn McCarney     // Make call to ObjectMapper to find all inventory items
1197*8fb49dd6SShawn McCarney     crow::connections::systemBus->async_method_call(
1198*8fb49dd6SShawn McCarney         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
1199*8fb49dd6SShawn McCarney         "/xyz/openbmc_project/object_mapper",
1200*8fb49dd6SShawn McCarney         "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 0, interfaces);
1201*8fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsConnections exit";
1202*8fb49dd6SShawn McCarney }
1203*8fb49dd6SShawn McCarney 
1204*8fb49dd6SShawn McCarney /**
1205*8fb49dd6SShawn McCarney  * @brief Gets inventory items associated with the specified sensors.
1206*8fb49dd6SShawn McCarney  *
1207*8fb49dd6SShawn McCarney  * Looks for ObjectMapper associations from the specified sensors to related
1208*8fb49dd6SShawn McCarney  * inventory items.  Builds map where key is sensor object path and value is
1209*8fb49dd6SShawn McCarney  * inventory item object path.
1210*8fb49dd6SShawn McCarney  *
1211*8fb49dd6SShawn McCarney  * Finds the inventory items asynchronously.  Invokes callback when information
1212*8fb49dd6SShawn McCarney  * has been obtained.
1213*8fb49dd6SShawn McCarney  *
1214*8fb49dd6SShawn McCarney  * The callback must have the following signature:
1215*8fb49dd6SShawn McCarney  *   @code
1216*8fb49dd6SShawn McCarney  *   callback(std::shared_ptr<boost::container::flat_map<
1217*8fb49dd6SShawn McCarney                   std::string, std::string>> sensorToInvMap)
1218*8fb49dd6SShawn McCarney  *   @endcode
1219*8fb49dd6SShawn McCarney  *
1220*8fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
1221*8fb49dd6SShawn McCarney  * @param sensorNames All sensors within the current chassis.
1222*8fb49dd6SShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
1223*8fb49dd6SShawn McCarney  * implements ObjectManager.
1224*8fb49dd6SShawn McCarney  * @param callback Callback to invoke when inventory items have been obtained.
1225*8fb49dd6SShawn McCarney  */
1226*8fb49dd6SShawn McCarney template <typename Callback>
1227*8fb49dd6SShawn McCarney static void getInventoryItems(
1228*8fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1229*8fb49dd6SShawn McCarney     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
1230*8fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1231*8fb49dd6SShawn McCarney         objectMgrPaths,
1232*8fb49dd6SShawn McCarney     Callback&& callback)
1233*8fb49dd6SShawn McCarney {
1234*8fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItems enter";
1235*8fb49dd6SShawn McCarney 
1236*8fb49dd6SShawn McCarney     // Response handler for GetManagedObjects
1237*8fb49dd6SShawn McCarney     auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
1238*8fb49dd6SShawn McCarney                         sensorNames](const boost::system::error_code ec,
1239*8fb49dd6SShawn McCarney                                      dbus::utility::ManagedObjectType& resp) {
1240*8fb49dd6SShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItems respHandler enter";
1241*8fb49dd6SShawn McCarney         if (ec)
1242*8fb49dd6SShawn McCarney         {
1243*8fb49dd6SShawn McCarney             BMCWEB_LOG_ERROR << "getInventoryItems respHandler DBus error "
1244*8fb49dd6SShawn McCarney                              << ec;
1245*8fb49dd6SShawn McCarney             messages::internalError(sensorsAsyncResp->res);
1246*8fb49dd6SShawn McCarney             return;
1247*8fb49dd6SShawn McCarney         }
1248*8fb49dd6SShawn McCarney 
1249*8fb49dd6SShawn McCarney         // Loop through returned object paths
1250*8fb49dd6SShawn McCarney         std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1251*8fb49dd6SShawn McCarney             sensorToInvMap = std::make_shared<
1252*8fb49dd6SShawn McCarney                 boost::container::flat_map<std::string, std::string>>();
1253*8fb49dd6SShawn McCarney         std::string sensorAssocPath;
1254*8fb49dd6SShawn McCarney         sensorAssocPath.reserve(128); // avoid memory allocations
1255*8fb49dd6SShawn McCarney         for (const auto& objDictEntry : resp)
1256*8fb49dd6SShawn McCarney         {
1257*8fb49dd6SShawn McCarney             const std::string& objPath =
1258*8fb49dd6SShawn McCarney                 static_cast<const std::string&>(objDictEntry.first);
1259*8fb49dd6SShawn McCarney             const boost::container::flat_map<
1260*8fb49dd6SShawn McCarney                 std::string, boost::container::flat_map<
1261*8fb49dd6SShawn McCarney                                  std::string, dbus::utility::DbusVariantType>>&
1262*8fb49dd6SShawn McCarney                 interfacesDict = objDictEntry.second;
1263*8fb49dd6SShawn McCarney 
1264*8fb49dd6SShawn McCarney             // If path is inventory association for one of the specified sensors
1265*8fb49dd6SShawn McCarney             for (const std::string& sensorName : *sensorNames)
1266*8fb49dd6SShawn McCarney             {
1267*8fb49dd6SShawn McCarney                 sensorAssocPath = sensorName;
1268*8fb49dd6SShawn McCarney                 sensorAssocPath += "/inventory";
1269*8fb49dd6SShawn McCarney                 if (objPath == sensorAssocPath)
1270*8fb49dd6SShawn McCarney                 {
1271*8fb49dd6SShawn McCarney                     // Get Association interface for object path
1272*8fb49dd6SShawn McCarney                     auto assocIt =
1273*8fb49dd6SShawn McCarney                         interfacesDict.find("xyz.openbmc_project.Association");
1274*8fb49dd6SShawn McCarney                     if (assocIt != interfacesDict.end())
1275*8fb49dd6SShawn McCarney                     {
1276*8fb49dd6SShawn McCarney                         // Get inventory item from end point
1277*8fb49dd6SShawn McCarney                         auto endpointsIt = assocIt->second.find("endpoints");
1278*8fb49dd6SShawn McCarney                         if (endpointsIt != assocIt->second.end())
1279*8fb49dd6SShawn McCarney                         {
1280*8fb49dd6SShawn McCarney                             const std::vector<std::string>* endpoints =
1281*8fb49dd6SShawn McCarney                                 std::get_if<std::vector<std::string>>(
1282*8fb49dd6SShawn McCarney                                     &endpointsIt->second);
1283*8fb49dd6SShawn McCarney                             if ((endpoints != nullptr) && !endpoints->empty())
1284*8fb49dd6SShawn McCarney                             {
1285*8fb49dd6SShawn McCarney                                 // Store sensor -> inventory item mapping
1286*8fb49dd6SShawn McCarney                                 const std::string& invItem = endpoints->front();
1287*8fb49dd6SShawn McCarney                                 (*sensorToInvMap)[sensorName] = invItem;
1288*8fb49dd6SShawn McCarney                             }
1289*8fb49dd6SShawn McCarney                         }
1290*8fb49dd6SShawn McCarney                     }
1291*8fb49dd6SShawn McCarney                     break;
1292*8fb49dd6SShawn McCarney                 }
1293*8fb49dd6SShawn McCarney             }
1294*8fb49dd6SShawn McCarney         }
1295*8fb49dd6SShawn McCarney 
1296*8fb49dd6SShawn McCarney         // Call callback if at least one inventory item was found
1297*8fb49dd6SShawn McCarney         if (!sensorToInvMap->empty())
1298*8fb49dd6SShawn McCarney         {
1299*8fb49dd6SShawn McCarney             callback(sensorToInvMap);
1300*8fb49dd6SShawn McCarney         }
1301*8fb49dd6SShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItems respHandler exit";
1302*8fb49dd6SShawn McCarney     };
1303*8fb49dd6SShawn McCarney 
1304*8fb49dd6SShawn McCarney     // Find DBus object path that implements ObjectManager for ObjectMapper
1305*8fb49dd6SShawn McCarney     std::string connection = "xyz.openbmc_project.ObjectMapper";
1306*8fb49dd6SShawn McCarney     auto iter = objectMgrPaths->find(connection);
1307*8fb49dd6SShawn McCarney     const std::string& objectMgrPath =
1308*8fb49dd6SShawn McCarney         (iter != objectMgrPaths->end()) ? iter->second : "/";
1309*8fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
1310*8fb49dd6SShawn McCarney                      << objectMgrPath;
1311*8fb49dd6SShawn McCarney 
1312*8fb49dd6SShawn McCarney     // Call GetManagedObjects on the ObjectMapper to get all associations
1313*8fb49dd6SShawn McCarney     crow::connections::systemBus->async_method_call(
1314*8fb49dd6SShawn McCarney         std::move(respHandler), connection, objectMgrPath,
1315*8fb49dd6SShawn McCarney         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1316*8fb49dd6SShawn McCarney 
1317*8fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItems exit";
1318*8fb49dd6SShawn McCarney }
1319*8fb49dd6SShawn McCarney 
1320*8fb49dd6SShawn McCarney /**
1321*8fb49dd6SShawn McCarney  * @brief Checks the status of inventory items associated with sensors.
1322*8fb49dd6SShawn McCarney  *
1323*8fb49dd6SShawn McCarney  * Finds the inventory items that are associated with the specified sensors.
1324*8fb49dd6SShawn McCarney  * Gets the status of those inventory items.
1325*8fb49dd6SShawn McCarney  *
1326*8fb49dd6SShawn McCarney  * If the inventory items are not present or functional, the sensor status is
1327*8fb49dd6SShawn McCarney  * updated in the JSON response.
1328*8fb49dd6SShawn McCarney  *
1329*8fb49dd6SShawn McCarney  * In D-Bus, the hardware present and functional properties are typically on the
1330*8fb49dd6SShawn McCarney  * inventory item rather than the sensor.
1331*8fb49dd6SShawn McCarney  *
1332*8fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
1333*8fb49dd6SShawn McCarney  * @param sensorNames All sensors within the current chassis.
1334*8fb49dd6SShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
1335*8fb49dd6SShawn McCarney  * implements ObjectManager.
1336*8fb49dd6SShawn McCarney  */
1337*8fb49dd6SShawn McCarney static void checkInventoryItemsStatus(
1338*8fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1339*8fb49dd6SShawn McCarney     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
1340*8fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1341*8fb49dd6SShawn McCarney         objectMgrPaths)
1342*8fb49dd6SShawn McCarney {
1343*8fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "checkInventoryItemsStatus enter";
1344*8fb49dd6SShawn McCarney     auto getInventoryItemsCb =
1345*8fb49dd6SShawn McCarney         [sensorsAsyncResp,
1346*8fb49dd6SShawn McCarney          objectMgrPaths](std::shared_ptr<
1347*8fb49dd6SShawn McCarney                          boost::container::flat_map<std::string, std::string>>
1348*8fb49dd6SShawn McCarney                              sensorToInvMap) {
1349*8fb49dd6SShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemsCb enter";
1350*8fb49dd6SShawn McCarney             auto getInventoryItemsConnectionsCb =
1351*8fb49dd6SShawn McCarney                 [sensorsAsyncResp, sensorToInvMap, objectMgrPaths](
1352*8fb49dd6SShawn McCarney                     std::shared_ptr<boost::container::flat_set<std::string>>
1353*8fb49dd6SShawn McCarney                         invConnections) {
1354*8fb49dd6SShawn McCarney                     BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb enter";
1355*8fb49dd6SShawn McCarney 
1356*8fb49dd6SShawn McCarney                     // Get status of inventory items and update sensors
1357*8fb49dd6SShawn McCarney                     getInventoryItemsStatus(sensorsAsyncResp, sensorToInvMap,
1358*8fb49dd6SShawn McCarney                                             invConnections, objectMgrPaths);
1359*8fb49dd6SShawn McCarney 
1360*8fb49dd6SShawn McCarney                     BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb exit";
1361*8fb49dd6SShawn McCarney                 };
1362*8fb49dd6SShawn McCarney 
1363*8fb49dd6SShawn McCarney             // Get connections that provide status of inventory items
1364*8fb49dd6SShawn McCarney             getInventoryItemsConnections(
1365*8fb49dd6SShawn McCarney                 sensorsAsyncResp, sensorToInvMap,
1366*8fb49dd6SShawn McCarney                 std::move(getInventoryItemsConnectionsCb));
1367*8fb49dd6SShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemsCb exit";
1368*8fb49dd6SShawn McCarney         };
1369*8fb49dd6SShawn McCarney 
1370*8fb49dd6SShawn McCarney     // Get inventory items that are associated with specified sensors
1371*8fb49dd6SShawn McCarney     getInventoryItems(sensorsAsyncResp, sensorNames, objectMgrPaths,
1372*8fb49dd6SShawn McCarney                       std::move(getInventoryItemsCb));
1373*8fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "checkInventoryItemsStatus exit";
1374*8fb49dd6SShawn McCarney }
1375*8fb49dd6SShawn McCarney 
1376*8fb49dd6SShawn McCarney /**
1377de629b6eSShawn McCarney  * @brief Gets the values of the specified sensors.
1378de629b6eSShawn McCarney  *
1379de629b6eSShawn McCarney  * Stores the results as JSON in the SensorsAsyncResp.
1380de629b6eSShawn McCarney  *
1381de629b6eSShawn McCarney  * Gets the sensor values asynchronously.  Stores the results later when the
1382de629b6eSShawn McCarney  * information has been obtained.
1383de629b6eSShawn McCarney  *
1384de629b6eSShawn McCarney  * The sensorNames set contains all sensors for the current chassis.
1385de629b6eSShawn McCarney  * SensorsAsyncResp contains the requested sensor types.  Only sensors of a
1386de629b6eSShawn McCarney  * requested type are included in the JSON output.
1387de629b6eSShawn McCarney  *
1388de629b6eSShawn McCarney  * To minimize the number of DBus calls, the DBus method
1389de629b6eSShawn McCarney  * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1390de629b6eSShawn McCarney  * values of all sensors provided by a connection (service).
1391de629b6eSShawn McCarney  *
1392de629b6eSShawn McCarney  * The connections set contains all the connections that provide sensor values.
1393de629b6eSShawn McCarney  *
1394de629b6eSShawn McCarney  * The objectMgrPaths map contains mappings from a connection name to the
1395de629b6eSShawn McCarney  * corresponding DBus object path that implements ObjectManager.
1396de629b6eSShawn McCarney  *
1397de629b6eSShawn McCarney  * @param SensorsAsyncResp Pointer to object holding response data.
1398de629b6eSShawn McCarney  * @param sensorNames All sensors within the current chassis.
1399de629b6eSShawn McCarney  * @param connections Connections that provide sensor values.
1400de629b6eSShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
1401de629b6eSShawn McCarney  * implements ObjectManager.
1402de629b6eSShawn McCarney  */
1403de629b6eSShawn McCarney void getSensorData(
1404de629b6eSShawn McCarney     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
140549c53ac9SJohnathan Mantey     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
1406de629b6eSShawn McCarney     const boost::container::flat_set<std::string>& connections,
1407*8fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1408*8fb49dd6SShawn McCarney         objectMgrPaths)
1409de629b6eSShawn McCarney {
1410de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getSensorData enter";
1411de629b6eSShawn McCarney     // Get managed objects from all services exposing sensors
1412de629b6eSShawn McCarney     for (const std::string& connection : connections)
1413de629b6eSShawn McCarney     {
1414de629b6eSShawn McCarney         // Response handler to process managed objects
1415*8fb49dd6SShawn McCarney         auto getManagedObjectsCb = [SensorsAsyncResp, sensorNames,
1416*8fb49dd6SShawn McCarney                                     objectMgrPaths](
1417de629b6eSShawn McCarney                                        const boost::system::error_code ec,
1418de629b6eSShawn McCarney                                        ManagedObjectsVectorType& resp) {
1419de629b6eSShawn McCarney             BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
1420de629b6eSShawn McCarney             if (ec)
1421de629b6eSShawn McCarney             {
1422de629b6eSShawn McCarney                 BMCWEB_LOG_ERROR << "getManagedObjectsCb DBUS error: " << ec;
1423de629b6eSShawn McCarney                 messages::internalError(SensorsAsyncResp->res);
1424de629b6eSShawn McCarney                 return;
1425de629b6eSShawn McCarney             }
1426de629b6eSShawn McCarney             // Go through all objects and update response with sensor data
1427de629b6eSShawn McCarney             for (const auto& objDictEntry : resp)
1428de629b6eSShawn McCarney             {
1429de629b6eSShawn McCarney                 const std::string& objPath =
1430de629b6eSShawn McCarney                     static_cast<const std::string&>(objDictEntry.first);
1431de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "getManagedObjectsCb parsing object "
1432de629b6eSShawn McCarney                                  << objPath;
1433de629b6eSShawn McCarney 
1434de629b6eSShawn McCarney                 std::vector<std::string> split;
1435de629b6eSShawn McCarney                 // Reserve space for
1436de629b6eSShawn McCarney                 // /xyz/openbmc_project/sensors/<name>/<subname>
1437de629b6eSShawn McCarney                 split.reserve(6);
1438de629b6eSShawn McCarney                 boost::algorithm::split(split, objPath, boost::is_any_of("/"));
1439de629b6eSShawn McCarney                 if (split.size() < 6)
1440de629b6eSShawn McCarney                 {
1441de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << "Got path that isn't long enough "
1442de629b6eSShawn McCarney                                      << objPath;
1443de629b6eSShawn McCarney                     continue;
1444de629b6eSShawn McCarney                 }
1445de629b6eSShawn McCarney                 // These indexes aren't intuitive, as boost::split puts an empty
1446de629b6eSShawn McCarney                 // string at the beginning
1447de629b6eSShawn McCarney                 const std::string& sensorType = split[4];
1448de629b6eSShawn McCarney                 const std::string& sensorName = split[5];
1449de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "sensorName " << sensorName
1450de629b6eSShawn McCarney                                  << " sensorType " << sensorType;
145149c53ac9SJohnathan Mantey                 if (sensorNames->find(objPath) == sensorNames->end())
1452de629b6eSShawn McCarney                 {
1453de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << sensorName << " not in sensor list ";
1454de629b6eSShawn McCarney                     continue;
1455de629b6eSShawn McCarney                 }
1456de629b6eSShawn McCarney 
1457de629b6eSShawn McCarney                 const char* fieldName = nullptr;
1458de629b6eSShawn McCarney                 if (sensorType == "temperature")
1459de629b6eSShawn McCarney                 {
1460de629b6eSShawn McCarney                     fieldName = "Temperatures";
1461de629b6eSShawn McCarney                 }
1462de629b6eSShawn McCarney                 else if (sensorType == "fan" || sensorType == "fan_tach" ||
1463de629b6eSShawn McCarney                          sensorType == "fan_pwm")
1464de629b6eSShawn McCarney                 {
1465de629b6eSShawn McCarney                     fieldName = "Fans";
1466de629b6eSShawn McCarney                 }
1467de629b6eSShawn McCarney                 else if (sensorType == "voltage")
1468de629b6eSShawn McCarney                 {
1469de629b6eSShawn McCarney                     fieldName = "Voltages";
1470de629b6eSShawn McCarney                 }
1471de629b6eSShawn McCarney                 else if (sensorType == "current")
1472de629b6eSShawn McCarney                 {
1473de629b6eSShawn McCarney                     fieldName = "PowerSupplies";
1474de629b6eSShawn McCarney                 }
1475de629b6eSShawn McCarney                 else if (sensorType == "power")
1476de629b6eSShawn McCarney                 {
1477028f7ebcSEddie James                     if (!sensorName.compare("total_power"))
1478028f7ebcSEddie James                     {
1479028f7ebcSEddie James                         fieldName = "PowerControl";
1480028f7ebcSEddie James                     }
1481028f7ebcSEddie James                     else
1482028f7ebcSEddie James                     {
1483de629b6eSShawn McCarney                         fieldName = "PowerSupplies";
1484de629b6eSShawn McCarney                     }
1485028f7ebcSEddie James                 }
1486de629b6eSShawn McCarney                 else
1487de629b6eSShawn McCarney                 {
1488de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << "Unsure how to handle sensorType "
1489de629b6eSShawn McCarney                                      << sensorType;
1490de629b6eSShawn McCarney                     continue;
1491de629b6eSShawn McCarney                 }
1492de629b6eSShawn McCarney 
1493de629b6eSShawn McCarney                 nlohmann::json& tempArray =
1494de629b6eSShawn McCarney                     SensorsAsyncResp->res.jsonValue[fieldName];
1495de629b6eSShawn McCarney 
149649c53ac9SJohnathan Mantey                 if (fieldName == "PowerSupplies" && !tempArray.empty())
149749c53ac9SJohnathan Mantey                 {
149849c53ac9SJohnathan Mantey                     // Power supplies put multiple "sensors" into a single power
149949c53ac9SJohnathan Mantey                     // supply entry, so only create the first one
150049c53ac9SJohnathan Mantey                 }
150149c53ac9SJohnathan Mantey                 else
150249c53ac9SJohnathan Mantey                 {
1503de629b6eSShawn McCarney                     tempArray.push_back(
150449c53ac9SJohnathan Mantey                         {{"@odata.id", "/redfish/v1/Chassis/" +
150549c53ac9SJohnathan Mantey                                            SensorsAsyncResp->chassisId + "/" +
150649c53ac9SJohnathan Mantey                                            SensorsAsyncResp->chassisSubNode +
150749c53ac9SJohnathan Mantey                                            "#/" + fieldName + "/"}});
150849c53ac9SJohnathan Mantey                 }
1509de629b6eSShawn McCarney                 nlohmann::json& sensorJson = tempArray.back();
1510de629b6eSShawn McCarney 
1511de629b6eSShawn McCarney                 objectInterfacesToJson(sensorName, sensorType,
1512de629b6eSShawn McCarney                                        objDictEntry.second, sensorJson);
1513de629b6eSShawn McCarney             }
151449c53ac9SJohnathan Mantey             if (SensorsAsyncResp.use_count() == 1)
151549c53ac9SJohnathan Mantey             {
151649c53ac9SJohnathan Mantey                 sortJSONResponse(SensorsAsyncResp);
1517*8fb49dd6SShawn McCarney                 checkInventoryItemsStatus(SensorsAsyncResp, sensorNames,
1518*8fb49dd6SShawn McCarney                                           objectMgrPaths);
151949c53ac9SJohnathan Mantey                 if (SensorsAsyncResp->chassisSubNode == "Thermal")
15208bd25ccdSJames Feist                 {
15218bd25ccdSJames Feist                     populateFanRedundancy(SensorsAsyncResp);
15228bd25ccdSJames Feist                 }
152349c53ac9SJohnathan Mantey             }
1524de629b6eSShawn McCarney             BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
1525de629b6eSShawn McCarney         };
1526de629b6eSShawn McCarney 
1527de629b6eSShawn McCarney         // Find DBus object path that implements ObjectManager for the current
1528de629b6eSShawn McCarney         // connection.  If no mapping found, default to "/".
1529*8fb49dd6SShawn McCarney         auto iter = objectMgrPaths->find(connection);
1530de629b6eSShawn McCarney         const std::string& objectMgrPath =
1531*8fb49dd6SShawn McCarney             (iter != objectMgrPaths->end()) ? iter->second : "/";
1532de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
1533de629b6eSShawn McCarney                          << objectMgrPath;
1534de629b6eSShawn McCarney 
1535de629b6eSShawn McCarney         crow::connections::systemBus->async_method_call(
1536de629b6eSShawn McCarney             getManagedObjectsCb, connection, objectMgrPath,
1537de629b6eSShawn McCarney             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1538de629b6eSShawn McCarney     };
1539de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getSensorData exit";
1540de629b6eSShawn McCarney }
1541de629b6eSShawn McCarney 
1542de629b6eSShawn McCarney /**
154308777fb0SLewanczyk, Dawid  * @brief Entry point for retrieving sensors data related to requested
154408777fb0SLewanczyk, Dawid  *        chassis.
1545588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
154608777fb0SLewanczyk, Dawid  */
15471abe55efSEd Tanous void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
15481abe55efSEd Tanous {
154955c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisData enter";
155049c53ac9SJohnathan Mantey     auto getChassisCb =
155149c53ac9SJohnathan Mantey         [SensorsAsyncResp](
155249c53ac9SJohnathan Mantey             std::shared_ptr<boost::container::flat_set<std::string>>
155308777fb0SLewanczyk, Dawid                 sensorNames) {
155455c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "getChassisCb enter";
1555*8fb49dd6SShawn McCarney             auto getConnectionCb = [SensorsAsyncResp, sensorNames](
1556*8fb49dd6SShawn McCarney                                        const boost::container::flat_set<
1557*8fb49dd6SShawn McCarney                                            std::string>& connections) {
155855c7b7a2SEd Tanous                 BMCWEB_LOG_DEBUG << "getConnectionCb enter";
1559de629b6eSShawn McCarney                 auto getObjectManagerPathsCb =
156049c53ac9SJohnathan Mantey                     [SensorsAsyncResp, sensorNames, connections](
1561*8fb49dd6SShawn McCarney                         std::shared_ptr<boost::container::flat_map<std::string,
1562*8fb49dd6SShawn McCarney                                                                    std::string>>
1563*8fb49dd6SShawn McCarney                             objectMgrPaths) {
1564de629b6eSShawn McCarney                         BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb enter";
156549c53ac9SJohnathan Mantey                         // Get sensor data and store results in JSON
156649c53ac9SJohnathan Mantey                         // response
1567de629b6eSShawn McCarney                         getSensorData(SensorsAsyncResp, sensorNames,
1568de629b6eSShawn McCarney                                       connections, objectMgrPaths);
1569de629b6eSShawn McCarney                         BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb exit";
157008777fb0SLewanczyk, Dawid                     };
1571de629b6eSShawn McCarney 
157249c53ac9SJohnathan Mantey                 // Get mapping from connection names to the DBus object
157349c53ac9SJohnathan Mantey                 // paths that implement the ObjectManager interface
1574de629b6eSShawn McCarney                 getObjectManagerPaths(SensorsAsyncResp,
1575de629b6eSShawn McCarney                                       std::move(getObjectManagerPathsCb));
157655c7b7a2SEd Tanous                 BMCWEB_LOG_DEBUG << "getConnectionCb exit";
157708777fb0SLewanczyk, Dawid             };
1578de629b6eSShawn McCarney 
1579de629b6eSShawn McCarney             // Get set of connections that provide sensor values
15801abe55efSEd Tanous             getConnections(SensorsAsyncResp, sensorNames,
15811abe55efSEd Tanous                            std::move(getConnectionCb));
158255c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "getChassisCb exit";
158308777fb0SLewanczyk, Dawid         };
15844f9a2130SJennifer Lee     SensorsAsyncResp->res.jsonValue["Redundancy"] = nlohmann::json::array();
158508777fb0SLewanczyk, Dawid 
158626f03899SShawn McCarney     // Get set of sensors in chassis
1587588c3f0dSKowalski, Kamil     getChassis(SensorsAsyncResp, std::move(getChassisCb));
158855c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisData exit";
158908777fb0SLewanczyk, Dawid };
159008777fb0SLewanczyk, Dawid 
1591413961deSRichard Marian Thomaiyar /**
159249c53ac9SJohnathan Mantey  * @brief Find the requested sensorName in the list of all sensors supplied by
159349c53ac9SJohnathan Mantey  * the chassis node
159449c53ac9SJohnathan Mantey  *
159549c53ac9SJohnathan Mantey  * @param sensorName   The sensor name supplied in the PATCH request
159649c53ac9SJohnathan Mantey  * @param sensorsList  The list of sensors managed by the chassis node
159749c53ac9SJohnathan Mantey  * @param sensorsModified  The list of sensors that were found as a result of
159849c53ac9SJohnathan Mantey  *                         repeated calls to this function
159949c53ac9SJohnathan Mantey  */
160049c53ac9SJohnathan Mantey bool findSensorNameUsingSensorPath(
16010a86febdSRichard Marian Thomaiyar     std::string_view sensorName,
160249c53ac9SJohnathan Mantey     boost::container::flat_set<std::string>& sensorsList,
160349c53ac9SJohnathan Mantey     boost::container::flat_set<std::string>& sensorsModified)
160449c53ac9SJohnathan Mantey {
16050a86febdSRichard Marian Thomaiyar     for (std::string_view chassisSensor : sensorsList)
160649c53ac9SJohnathan Mantey     {
16070a86febdSRichard Marian Thomaiyar         std::size_t pos = chassisSensor.rfind("/");
16080a86febdSRichard Marian Thomaiyar         if (pos >= (chassisSensor.size() - 1))
160949c53ac9SJohnathan Mantey         {
161049c53ac9SJohnathan Mantey             continue;
161149c53ac9SJohnathan Mantey         }
16120a86febdSRichard Marian Thomaiyar         std::string_view thisSensorName = chassisSensor.substr(pos + 1);
161349c53ac9SJohnathan Mantey         if (thisSensorName == sensorName)
161449c53ac9SJohnathan Mantey         {
161549c53ac9SJohnathan Mantey             sensorsModified.emplace(chassisSensor);
161649c53ac9SJohnathan Mantey             return true;
161749c53ac9SJohnathan Mantey         }
161849c53ac9SJohnathan Mantey     }
161949c53ac9SJohnathan Mantey     return false;
162049c53ac9SJohnathan Mantey }
162149c53ac9SJohnathan Mantey 
162249c53ac9SJohnathan Mantey /**
1623413961deSRichard Marian Thomaiyar  * @brief Entry point for overriding sensor values of given sensor
1624413961deSRichard Marian Thomaiyar  *
1625413961deSRichard Marian Thomaiyar  * @param res   response object
1626413961deSRichard Marian Thomaiyar  * @param req   request object
1627413961deSRichard Marian Thomaiyar  * @param params   parameter passed for CRUD
1628413961deSRichard Marian Thomaiyar  * @param typeList   TypeList of sensors for the resource queried
1629413961deSRichard Marian Thomaiyar  * @param chassisSubNode   Chassis Node for which the query has to happen
1630413961deSRichard Marian Thomaiyar  */
1631413961deSRichard Marian Thomaiyar void setSensorOverride(crow::Response& res, const crow::Request& req,
1632413961deSRichard Marian Thomaiyar                        const std::vector<std::string>& params,
1633b01bf299SEd Tanous                        const std::initializer_list<const char*> typeList,
1634413961deSRichard Marian Thomaiyar                        const std::string& chassisSubNode)
1635413961deSRichard Marian Thomaiyar {
1636413961deSRichard Marian Thomaiyar 
1637413961deSRichard Marian Thomaiyar     // TODO: Need to figure out dynamic way to restrict patch (Set Sensor
1638413961deSRichard Marian Thomaiyar     // override) based on another d-bus announcement to be more generic.
1639413961deSRichard Marian Thomaiyar     if (params.size() != 1)
1640413961deSRichard Marian Thomaiyar     {
1641413961deSRichard Marian Thomaiyar         messages::internalError(res);
1642413961deSRichard Marian Thomaiyar         res.end();
1643413961deSRichard Marian Thomaiyar         return;
1644413961deSRichard Marian Thomaiyar     }
1645f65af9e8SRichard Marian Thomaiyar 
1646f65af9e8SRichard Marian Thomaiyar     std::unordered_map<std::string, std::vector<nlohmann::json>> allCollections;
1647f65af9e8SRichard Marian Thomaiyar     std::optional<std::vector<nlohmann::json>> temperatureCollections;
1648f65af9e8SRichard Marian Thomaiyar     std::optional<std::vector<nlohmann::json>> fanCollections;
1649f65af9e8SRichard Marian Thomaiyar     std::vector<nlohmann::json> voltageCollections;
1650f65af9e8SRichard Marian Thomaiyar     BMCWEB_LOG_INFO << "setSensorOverride for subNode" << chassisSubNode
1651f65af9e8SRichard Marian Thomaiyar                     << "\n";
1652f65af9e8SRichard Marian Thomaiyar 
1653413961deSRichard Marian Thomaiyar     if (chassisSubNode == "Thermal")
1654413961deSRichard Marian Thomaiyar     {
1655f65af9e8SRichard Marian Thomaiyar         if (!json_util::readJson(req, res, "Temperatures",
1656f65af9e8SRichard Marian Thomaiyar                                  temperatureCollections, "Fans",
1657f65af9e8SRichard Marian Thomaiyar                                  fanCollections))
1658f65af9e8SRichard Marian Thomaiyar         {
1659f65af9e8SRichard Marian Thomaiyar             return;
1660f65af9e8SRichard Marian Thomaiyar         }
1661f65af9e8SRichard Marian Thomaiyar         if (!temperatureCollections && !fanCollections)
1662f65af9e8SRichard Marian Thomaiyar         {
1663f65af9e8SRichard Marian Thomaiyar             messages::resourceNotFound(res, "Thermal",
1664f65af9e8SRichard Marian Thomaiyar                                        "Temperatures / Voltages");
1665f65af9e8SRichard Marian Thomaiyar             res.end();
1666f65af9e8SRichard Marian Thomaiyar             return;
1667f65af9e8SRichard Marian Thomaiyar         }
1668f65af9e8SRichard Marian Thomaiyar         if (temperatureCollections)
1669f65af9e8SRichard Marian Thomaiyar         {
1670f65af9e8SRichard Marian Thomaiyar             allCollections.emplace("Temperatures",
1671f65af9e8SRichard Marian Thomaiyar                                    *std::move(temperatureCollections));
1672f65af9e8SRichard Marian Thomaiyar         }
1673f65af9e8SRichard Marian Thomaiyar         if (fanCollections)
1674f65af9e8SRichard Marian Thomaiyar         {
1675f65af9e8SRichard Marian Thomaiyar             allCollections.emplace("Fans", *std::move(fanCollections));
1676f65af9e8SRichard Marian Thomaiyar         }
1677413961deSRichard Marian Thomaiyar     }
1678413961deSRichard Marian Thomaiyar     else if (chassisSubNode == "Power")
1679413961deSRichard Marian Thomaiyar     {
1680f65af9e8SRichard Marian Thomaiyar         if (!json_util::readJson(req, res, "Voltages", voltageCollections))
1681f65af9e8SRichard Marian Thomaiyar         {
1682f65af9e8SRichard Marian Thomaiyar             return;
1683f65af9e8SRichard Marian Thomaiyar         }
1684f65af9e8SRichard Marian Thomaiyar         allCollections.emplace("Voltages", std::move(voltageCollections));
1685413961deSRichard Marian Thomaiyar     }
1686413961deSRichard Marian Thomaiyar     else
1687413961deSRichard Marian Thomaiyar     {
1688413961deSRichard Marian Thomaiyar         res.result(boost::beast::http::status::not_found);
1689413961deSRichard Marian Thomaiyar         res.end();
1690413961deSRichard Marian Thomaiyar         return;
1691413961deSRichard Marian Thomaiyar     }
1692413961deSRichard Marian Thomaiyar 
1693f65af9e8SRichard Marian Thomaiyar     const char* propertyValueName;
1694f65af9e8SRichard Marian Thomaiyar     std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
1695413961deSRichard Marian Thomaiyar     std::string memberId;
1696413961deSRichard Marian Thomaiyar     double value;
1697f65af9e8SRichard Marian Thomaiyar     for (auto& collectionItems : allCollections)
1698f65af9e8SRichard Marian Thomaiyar     {
1699f65af9e8SRichard Marian Thomaiyar         if (collectionItems.first == "Temperatures")
1700f65af9e8SRichard Marian Thomaiyar         {
1701f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingCelsius";
1702f65af9e8SRichard Marian Thomaiyar         }
1703f65af9e8SRichard Marian Thomaiyar         else if (collectionItems.first == "Fans")
1704f65af9e8SRichard Marian Thomaiyar         {
1705f65af9e8SRichard Marian Thomaiyar             propertyValueName = "Reading";
1706f65af9e8SRichard Marian Thomaiyar         }
1707f65af9e8SRichard Marian Thomaiyar         else
1708f65af9e8SRichard Marian Thomaiyar         {
1709f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingVolts";
1710f65af9e8SRichard Marian Thomaiyar         }
1711f65af9e8SRichard Marian Thomaiyar         for (auto& item : collectionItems.second)
1712f65af9e8SRichard Marian Thomaiyar         {
1713f65af9e8SRichard Marian Thomaiyar             if (!json_util::readJson(item, res, "MemberId", memberId,
1714413961deSRichard Marian Thomaiyar                                      propertyValueName, value))
1715413961deSRichard Marian Thomaiyar             {
1716413961deSRichard Marian Thomaiyar                 return;
1717413961deSRichard Marian Thomaiyar             }
1718f65af9e8SRichard Marian Thomaiyar             overrideMap.emplace(memberId,
1719f65af9e8SRichard Marian Thomaiyar                                 std::make_pair(value, collectionItems.first));
1720f65af9e8SRichard Marian Thomaiyar         }
1721f65af9e8SRichard Marian Thomaiyar     }
1722413961deSRichard Marian Thomaiyar     const std::string& chassisName = params[0];
1723413961deSRichard Marian Thomaiyar     auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
1724413961deSRichard Marian Thomaiyar         res, chassisName, typeList, chassisSubNode);
172549c53ac9SJohnathan Mantey     auto getChassisSensorListCb = [sensorAsyncResp,
172649c53ac9SJohnathan Mantey                                    overrideMap](const std::shared_ptr<
172749c53ac9SJohnathan Mantey                                                 boost::container::flat_set<
172849c53ac9SJohnathan Mantey                                                     std::string>>
172949c53ac9SJohnathan Mantey                                                     sensorsList) {
173049c53ac9SJohnathan Mantey         // Match sensor names in the PATCH request to those managed by the
173149c53ac9SJohnathan Mantey         // chassis node
173249c53ac9SJohnathan Mantey         const std::shared_ptr<boost::container::flat_set<std::string>>
173349c53ac9SJohnathan Mantey             sensorNames =
173449c53ac9SJohnathan Mantey                 std::make_shared<boost::container::flat_set<std::string>>();
1735f65af9e8SRichard Marian Thomaiyar         for (const auto& item : overrideMap)
1736413961deSRichard Marian Thomaiyar         {
1737f65af9e8SRichard Marian Thomaiyar             const auto& sensor = item.first;
173849c53ac9SJohnathan Mantey             if (!findSensorNameUsingSensorPath(sensor, *sensorsList,
173949c53ac9SJohnathan Mantey                                                *sensorNames))
1740f65af9e8SRichard Marian Thomaiyar             {
1741f65af9e8SRichard Marian Thomaiyar                 BMCWEB_LOG_INFO << "Unable to find memberId " << item.first;
1742413961deSRichard Marian Thomaiyar                 messages::resourceNotFound(sensorAsyncResp->res,
1743f65af9e8SRichard Marian Thomaiyar                                            item.second.second, item.first);
1744413961deSRichard Marian Thomaiyar                 return;
1745413961deSRichard Marian Thomaiyar             }
1746f65af9e8SRichard Marian Thomaiyar         }
1747413961deSRichard Marian Thomaiyar         // Get the connection to which the memberId belongs
1748413961deSRichard Marian Thomaiyar         auto getObjectsWithConnectionCb =
1749f65af9e8SRichard Marian Thomaiyar             [sensorAsyncResp, overrideMap](
1750413961deSRichard Marian Thomaiyar                 const boost::container::flat_set<std::string>& connections,
1751413961deSRichard Marian Thomaiyar                 const std::set<std::pair<std::string, std::string>>&
1752413961deSRichard Marian Thomaiyar                     objectsWithConnection) {
1753f65af9e8SRichard Marian Thomaiyar                 if (objectsWithConnection.size() != overrideMap.size())
1754413961deSRichard Marian Thomaiyar                 {
1755413961deSRichard Marian Thomaiyar                     BMCWEB_LOG_INFO
1756f65af9e8SRichard Marian Thomaiyar                         << "Unable to find all objects with proper connection "
1757f65af9e8SRichard Marian Thomaiyar                         << objectsWithConnection.size() << " requested "
1758f65af9e8SRichard Marian Thomaiyar                         << overrideMap.size() << "\n";
1759413961deSRichard Marian Thomaiyar                     messages::resourceNotFound(
1760413961deSRichard Marian Thomaiyar                         sensorAsyncResp->res,
1761413961deSRichard Marian Thomaiyar                         sensorAsyncResp->chassisSubNode == "Thermal"
1762413961deSRichard Marian Thomaiyar                             ? "Temperatures"
1763413961deSRichard Marian Thomaiyar                             : "Voltages",
1764f65af9e8SRichard Marian Thomaiyar                         "Count");
1765f65af9e8SRichard Marian Thomaiyar                     return;
1766f65af9e8SRichard Marian Thomaiyar                 }
1767f65af9e8SRichard Marian Thomaiyar                 for (const auto& item : objectsWithConnection)
1768f65af9e8SRichard Marian Thomaiyar                 {
1769f65af9e8SRichard Marian Thomaiyar 
1770f65af9e8SRichard Marian Thomaiyar                     auto lastPos = item.first.rfind('/');
1771f65af9e8SRichard Marian Thomaiyar                     if (lastPos == std::string::npos)
1772f65af9e8SRichard Marian Thomaiyar                     {
1773f65af9e8SRichard Marian Thomaiyar                         messages::internalError(sensorAsyncResp->res);
1774f65af9e8SRichard Marian Thomaiyar                         return;
1775f65af9e8SRichard Marian Thomaiyar                     }
1776f65af9e8SRichard Marian Thomaiyar                     std::string sensorName = item.first.substr(lastPos + 1);
1777f65af9e8SRichard Marian Thomaiyar 
1778f65af9e8SRichard Marian Thomaiyar                     const auto& iterator = overrideMap.find(sensorName);
1779f65af9e8SRichard Marian Thomaiyar                     if (iterator == overrideMap.end())
1780f65af9e8SRichard Marian Thomaiyar                     {
1781f65af9e8SRichard Marian Thomaiyar                         BMCWEB_LOG_INFO << "Unable to find sensor object"
1782f65af9e8SRichard Marian Thomaiyar                                         << item.first << "\n";
1783f65af9e8SRichard Marian Thomaiyar                         messages::internalError(sensorAsyncResp->res);
1784413961deSRichard Marian Thomaiyar                         return;
1785413961deSRichard Marian Thomaiyar                     }
1786413961deSRichard Marian Thomaiyar                     crow::connections::systemBus->async_method_call(
1787f65af9e8SRichard Marian Thomaiyar                         [sensorAsyncResp](const boost::system::error_code ec) {
1788413961deSRichard Marian Thomaiyar                             if (ec)
1789413961deSRichard Marian Thomaiyar                             {
1790413961deSRichard Marian Thomaiyar                                 BMCWEB_LOG_DEBUG
1791f65af9e8SRichard Marian Thomaiyar                                     << "setOverrideValueStatus DBUS error: "
1792413961deSRichard Marian Thomaiyar                                     << ec;
1793413961deSRichard Marian Thomaiyar                                 messages::internalError(sensorAsyncResp->res);
1794413961deSRichard Marian Thomaiyar                                 return;
1795413961deSRichard Marian Thomaiyar                             }
1796413961deSRichard Marian Thomaiyar                         },
1797f65af9e8SRichard Marian Thomaiyar                         item.second, item.first,
1798413961deSRichard Marian Thomaiyar                         "org.freedesktop.DBus.Properties", "Set",
1799413961deSRichard Marian Thomaiyar                         "xyz.openbmc_project.Sensor.Value", "Value",
1800f65af9e8SRichard Marian Thomaiyar                         sdbusplus::message::variant<double>(
1801f65af9e8SRichard Marian Thomaiyar                             iterator->second.first));
1802f65af9e8SRichard Marian Thomaiyar                 }
1803413961deSRichard Marian Thomaiyar             };
1804413961deSRichard Marian Thomaiyar         // Get object with connection for the given sensor name
1805413961deSRichard Marian Thomaiyar         getObjectsWithConnection(sensorAsyncResp, sensorNames,
1806413961deSRichard Marian Thomaiyar                                  std::move(getObjectsWithConnectionCb));
1807413961deSRichard Marian Thomaiyar     };
1808413961deSRichard Marian Thomaiyar     // get full sensor list for the given chassisId and cross verify the sensor.
1809413961deSRichard Marian Thomaiyar     getChassis(sensorAsyncResp, std::move(getChassisSensorListCb));
1810413961deSRichard Marian Thomaiyar }
1811413961deSRichard Marian Thomaiyar 
181208777fb0SLewanczyk, Dawid } // namespace redfish
1813