xref: /openbmc/bmcweb/features/redfish/lib/sensors.hpp (revision adc4f0db57568c5e5d2a3398fce00dbb050a3b72)
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 
35*adc4f0dbSShawn McCarney using SensorVariant =
36*adc4f0dbSShawn McCarney     std::variant<int64_t, double, uint32_t, bool, std::string>;
37aa2e59c1SEd Tanous 
3808777fb0SLewanczyk, Dawid using ManagedObjectsVectorType = std::vector<std::pair<
39aa2e59c1SEd Tanous     sdbusplus::message::object_path,
4008777fb0SLewanczyk, Dawid     boost::container::flat_map<
41aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>>>;
4208777fb0SLewanczyk, Dawid 
4308777fb0SLewanczyk, Dawid /**
44588c3f0dSKowalski, Kamil  * SensorsAsyncResp
4508777fb0SLewanczyk, Dawid  * Gathers data needed for response processing after async calls are done
4608777fb0SLewanczyk, Dawid  */
471abe55efSEd Tanous class SensorsAsyncResp
481abe55efSEd Tanous {
4908777fb0SLewanczyk, Dawid   public:
5055c7b7a2SEd Tanous     SensorsAsyncResp(crow::Response& response, const std::string& chassisId,
5185e1424fSEd Tanous                      const std::vector<const char*> types,
522474adfaSEd Tanous                      const std::string& subNode) :
5343b761d0SEd Tanous         res(response),
5443b761d0SEd Tanous         chassisId(chassisId), types(types), chassisSubNode(subNode)
551abe55efSEd Tanous     {
5608777fb0SLewanczyk, Dawid     }
5708777fb0SLewanczyk, Dawid 
581abe55efSEd Tanous     ~SensorsAsyncResp()
591abe55efSEd Tanous     {
601abe55efSEd Tanous         if (res.result() == boost::beast::http::status::internal_server_error)
611abe55efSEd Tanous         {
621abe55efSEd Tanous             // Reset the json object to clear out any data that made it in
631abe55efSEd Tanous             // before the error happened todo(ed) handle error condition with
641abe55efSEd Tanous             // proper code
6555c7b7a2SEd Tanous             res.jsonValue = nlohmann::json::object();
6608777fb0SLewanczyk, Dawid         }
6708777fb0SLewanczyk, Dawid         res.end();
6808777fb0SLewanczyk, Dawid     }
69588c3f0dSKowalski, Kamil 
7055c7b7a2SEd Tanous     crow::Response& res;
71588c3f0dSKowalski, Kamil     std::string chassisId{};
7208777fb0SLewanczyk, Dawid     const std::vector<const char*> types;
732474adfaSEd Tanous     std::string chassisSubNode{};
7408777fb0SLewanczyk, Dawid };
7508777fb0SLewanczyk, Dawid 
7608777fb0SLewanczyk, Dawid /**
77*adc4f0dbSShawn McCarney  * D-Bus inventory item associated with one or more sensors.
78*adc4f0dbSShawn McCarney  */
79*adc4f0dbSShawn McCarney class InventoryItem
80*adc4f0dbSShawn McCarney {
81*adc4f0dbSShawn McCarney   public:
82*adc4f0dbSShawn McCarney     InventoryItem(const std::string& objPath) :
83*adc4f0dbSShawn McCarney         objectPath(objPath), name(), isPresent(true), isFunctional(true),
84*adc4f0dbSShawn McCarney         isPowerSupply(false), manufacturer(), model(), partNumber(),
85*adc4f0dbSShawn McCarney         serialNumber(), sensors()
86*adc4f0dbSShawn McCarney     {
87*adc4f0dbSShawn McCarney         // Set inventory item name to last node of object path
88*adc4f0dbSShawn McCarney         auto pos = objectPath.rfind('/');
89*adc4f0dbSShawn McCarney         if ((pos != std::string::npos) && ((pos + 1) < objectPath.size()))
90*adc4f0dbSShawn McCarney         {
91*adc4f0dbSShawn McCarney             name = objectPath.substr(pos + 1);
92*adc4f0dbSShawn McCarney         }
93*adc4f0dbSShawn McCarney     }
94*adc4f0dbSShawn McCarney 
95*adc4f0dbSShawn McCarney     std::string objectPath;
96*adc4f0dbSShawn McCarney     std::string name;
97*adc4f0dbSShawn McCarney     bool isPresent;
98*adc4f0dbSShawn McCarney     bool isFunctional;
99*adc4f0dbSShawn McCarney     bool isPowerSupply;
100*adc4f0dbSShawn McCarney     std::string manufacturer;
101*adc4f0dbSShawn McCarney     std::string model;
102*adc4f0dbSShawn McCarney     std::string partNumber;
103*adc4f0dbSShawn McCarney     std::string serialNumber;
104*adc4f0dbSShawn McCarney     std::set<std::string> sensors;
105*adc4f0dbSShawn McCarney };
106*adc4f0dbSShawn McCarney 
107*adc4f0dbSShawn McCarney /**
108413961deSRichard Marian Thomaiyar  * @brief Get objects with connection necessary for sensors
109588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp Pointer to object holding response data
11008777fb0SLewanczyk, Dawid  * @param sensorNames Sensors retrieved from chassis
11108777fb0SLewanczyk, Dawid  * @param callback Callback for processing gathered connections
11208777fb0SLewanczyk, Dawid  */
11308777fb0SLewanczyk, Dawid template <typename Callback>
114413961deSRichard Marian Thomaiyar void getObjectsWithConnection(
115413961deSRichard Marian Thomaiyar     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
11649c53ac9SJohnathan Mantey     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
1171abe55efSEd Tanous     Callback&& callback)
1181abe55efSEd Tanous {
119413961deSRichard Marian Thomaiyar     BMCWEB_LOG_DEBUG << "getObjectsWithConnection enter";
12003b5bae3SJames Feist     const std::string path = "/xyz/openbmc_project/sensors";
12108777fb0SLewanczyk, Dawid     const std::array<std::string, 1> interfaces = {
12208777fb0SLewanczyk, Dawid         "xyz.openbmc_project.Sensor.Value"};
12308777fb0SLewanczyk, Dawid 
12408777fb0SLewanczyk, Dawid     // Response handler for parsing objects subtree
1251abe55efSEd Tanous     auto respHandler = [callback{std::move(callback)}, SensorsAsyncResp,
1261abe55efSEd Tanous                         sensorNames](const boost::system::error_code ec,
1271abe55efSEd Tanous                                      const GetSubTreeType& subtree) {
128413961deSRichard Marian Thomaiyar         BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler enter";
1291abe55efSEd Tanous         if (ec)
1301abe55efSEd Tanous         {
1315f7d88c4SEd Tanous             messages::internalError(SensorsAsyncResp->res);
132413961deSRichard Marian Thomaiyar             BMCWEB_LOG_ERROR
133413961deSRichard Marian Thomaiyar                 << "getObjectsWithConnection resp_handler: Dbus error " << ec;
13408777fb0SLewanczyk, Dawid             return;
13508777fb0SLewanczyk, Dawid         }
13608777fb0SLewanczyk, Dawid 
13755c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
13808777fb0SLewanczyk, Dawid 
13908777fb0SLewanczyk, Dawid         // Make unique list of connections only for requested sensor types and
14008777fb0SLewanczyk, Dawid         // found in the chassis
14108777fb0SLewanczyk, Dawid         boost::container::flat_set<std::string> connections;
142413961deSRichard Marian Thomaiyar         std::set<std::pair<std::string, std::string>> objectsWithConnection;
1431abe55efSEd Tanous         // Intrinsic to avoid malloc.  Most systems will have < 8 sensor
1441abe55efSEd Tanous         // producers
14508777fb0SLewanczyk, Dawid         connections.reserve(8);
14608777fb0SLewanczyk, Dawid 
14749c53ac9SJohnathan Mantey         BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames->size();
14849c53ac9SJohnathan Mantey         for (const std::string& tsensor : *sensorNames)
1491abe55efSEd Tanous         {
15055c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor;
15108777fb0SLewanczyk, Dawid         }
15208777fb0SLewanczyk, Dawid 
15308777fb0SLewanczyk, Dawid         for (const std::pair<
15408777fb0SLewanczyk, Dawid                  std::string,
15508777fb0SLewanczyk, Dawid                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
1561abe55efSEd Tanous                  object : subtree)
1571abe55efSEd Tanous         {
15849c53ac9SJohnathan Mantey             if (sensorNames->find(object.first) != sensorNames->end())
1591abe55efSEd Tanous             {
16049c53ac9SJohnathan Mantey                 for (const std::pair<std::string, std::vector<std::string>>&
1611abe55efSEd Tanous                          objData : object.second)
1621abe55efSEd Tanous                 {
16349c53ac9SJohnathan Mantey                     BMCWEB_LOG_DEBUG << "Adding connection: " << objData.first;
16408777fb0SLewanczyk, Dawid                     connections.insert(objData.first);
165de629b6eSShawn McCarney                     objectsWithConnection.insert(
166de629b6eSShawn McCarney                         std::make_pair(object.first, objData.first));
16708777fb0SLewanczyk, Dawid                 }
16808777fb0SLewanczyk, Dawid             }
16908777fb0SLewanczyk, Dawid         }
17055c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections";
171413961deSRichard Marian Thomaiyar         callback(std::move(connections), std::move(objectsWithConnection));
172413961deSRichard Marian Thomaiyar         BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler exit";
17308777fb0SLewanczyk, Dawid     };
17408777fb0SLewanczyk, Dawid     // Make call to ObjectMapper to find all sensors objects
17555c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
17655c7b7a2SEd Tanous         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
1771abe55efSEd Tanous         "/xyz/openbmc_project/object_mapper",
1781abe55efSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 2, interfaces);
179413961deSRichard Marian Thomaiyar     BMCWEB_LOG_DEBUG << "getObjectsWithConnection exit";
180413961deSRichard Marian Thomaiyar }
181413961deSRichard Marian Thomaiyar 
182413961deSRichard Marian Thomaiyar /**
183413961deSRichard Marian Thomaiyar  * @brief Create connections necessary for sensors
184413961deSRichard Marian Thomaiyar  * @param SensorsAsyncResp Pointer to object holding response data
185413961deSRichard Marian Thomaiyar  * @param sensorNames Sensors retrieved from chassis
186413961deSRichard Marian Thomaiyar  * @param callback Callback for processing gathered connections
187413961deSRichard Marian Thomaiyar  */
188413961deSRichard Marian Thomaiyar template <typename Callback>
18949c53ac9SJohnathan Mantey void getConnections(
19049c53ac9SJohnathan Mantey     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
19149c53ac9SJohnathan Mantey     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
192413961deSRichard Marian Thomaiyar     Callback&& callback)
193413961deSRichard Marian Thomaiyar {
194413961deSRichard Marian Thomaiyar     auto objectsWithConnectionCb =
195413961deSRichard Marian Thomaiyar         [callback](const boost::container::flat_set<std::string>& connections,
196413961deSRichard Marian Thomaiyar                    const std::set<std::pair<std::string, std::string>>&
197413961deSRichard Marian Thomaiyar                        objectsWithConnection) {
198413961deSRichard Marian Thomaiyar             callback(std::move(connections));
199413961deSRichard Marian Thomaiyar         };
200413961deSRichard Marian Thomaiyar     getObjectsWithConnection(SensorsAsyncResp, sensorNames,
201413961deSRichard Marian Thomaiyar                              std::move(objectsWithConnectionCb));
20208777fb0SLewanczyk, Dawid }
20308777fb0SLewanczyk, Dawid 
20408777fb0SLewanczyk, Dawid /**
20549c53ac9SJohnathan Mantey  * @brief Shrinks the list of sensors for processing
20649c53ac9SJohnathan Mantey  * @param SensorsAysncResp  The class holding the Redfish response
20749c53ac9SJohnathan Mantey  * @param allSensors  A list of all the sensors associated to the
20849c53ac9SJohnathan Mantey  * chassis element (i.e. baseboard, front panel, etc...)
20949c53ac9SJohnathan Mantey  * @param activeSensors A list that is a reduction of the incoming
21049c53ac9SJohnathan Mantey  * allSensors list.  Eliminate Thermal sensors when a Power request is
21149c53ac9SJohnathan Mantey  * made, and eliminate Power sensors when a Thermal request is made.
21249c53ac9SJohnathan Mantey  */
21349c53ac9SJohnathan Mantey void reduceSensorList(
21449c53ac9SJohnathan Mantey     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
21549c53ac9SJohnathan Mantey     const std::vector<std::string>* allSensors,
21649c53ac9SJohnathan Mantey     std::shared_ptr<boost::container::flat_set<std::string>> activeSensors)
21749c53ac9SJohnathan Mantey {
21849c53ac9SJohnathan Mantey     if (SensorsAsyncResp == nullptr)
21949c53ac9SJohnathan Mantey     {
22049c53ac9SJohnathan Mantey         return;
22149c53ac9SJohnathan Mantey     }
22249c53ac9SJohnathan Mantey     if ((allSensors == nullptr) || (activeSensors == nullptr))
22349c53ac9SJohnathan Mantey     {
22449c53ac9SJohnathan Mantey         messages::resourceNotFound(
22549c53ac9SJohnathan Mantey             SensorsAsyncResp->res, SensorsAsyncResp->chassisSubNode,
22649c53ac9SJohnathan Mantey             SensorsAsyncResp->chassisSubNode == "Thermal" ? "Temperatures"
22749c53ac9SJohnathan Mantey                                                           : "Voltages");
22849c53ac9SJohnathan Mantey 
22949c53ac9SJohnathan Mantey         return;
23049c53ac9SJohnathan Mantey     }
23149c53ac9SJohnathan Mantey     if (allSensors->empty())
23249c53ac9SJohnathan Mantey     {
23349c53ac9SJohnathan Mantey         // Nothing to do, the activeSensors object is also empty
23449c53ac9SJohnathan Mantey         return;
23549c53ac9SJohnathan Mantey     }
23649c53ac9SJohnathan Mantey 
23749c53ac9SJohnathan Mantey     for (const char* type : SensorsAsyncResp->types)
23849c53ac9SJohnathan Mantey     {
23949c53ac9SJohnathan Mantey         for (const std::string& sensor : *allSensors)
24049c53ac9SJohnathan Mantey         {
24149c53ac9SJohnathan Mantey             if (boost::starts_with(sensor, type))
24249c53ac9SJohnathan Mantey             {
24349c53ac9SJohnathan Mantey                 activeSensors->emplace(sensor);
24449c53ac9SJohnathan Mantey             }
24549c53ac9SJohnathan Mantey         }
24649c53ac9SJohnathan Mantey     }
24749c53ac9SJohnathan Mantey }
24849c53ac9SJohnathan Mantey 
24949c53ac9SJohnathan Mantey /**
25008777fb0SLewanczyk, Dawid  * @brief Retrieves requested chassis sensors and redundancy data from DBus .
251588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
25208777fb0SLewanczyk, Dawid  * @param callback  Callback for next step in gathered sensor processing
25308777fb0SLewanczyk, Dawid  */
25408777fb0SLewanczyk, Dawid template <typename Callback>
25549c53ac9SJohnathan Mantey void getChassis(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
2561abe55efSEd Tanous                 Callback&& callback)
2571abe55efSEd Tanous {
25855c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis enter";
259*adc4f0dbSShawn McCarney     const std::array<const char*, 2> interfaces = {
26049c53ac9SJohnathan Mantey         "xyz.openbmc_project.Inventory.Item.Board",
261*adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Item.Chassis"};
26249c53ac9SJohnathan Mantey     auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp](
26349c53ac9SJohnathan Mantey                            const boost::system::error_code ec,
26449c53ac9SJohnathan Mantey                            const std::vector<std::string>& chassisPaths) {
26555c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassis respHandler enter";
2661abe55efSEd Tanous         if (ec)
2671abe55efSEd Tanous         {
26855c7b7a2SEd Tanous             BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec;
26949c53ac9SJohnathan Mantey             messages::internalError(sensorsAsyncResp->res);
27008777fb0SLewanczyk, Dawid             return;
27108777fb0SLewanczyk, Dawid         }
27208777fb0SLewanczyk, Dawid 
27349c53ac9SJohnathan Mantey         const std::string* chassisPath = nullptr;
27449c53ac9SJohnathan Mantey         std::string chassisName;
27549c53ac9SJohnathan Mantey         for (const std::string& chassis : chassisPaths)
2761abe55efSEd Tanous         {
27749c53ac9SJohnathan Mantey             std::size_t lastPos = chassis.rfind("/");
27849c53ac9SJohnathan Mantey             if (lastPos == std::string::npos)
2791abe55efSEd Tanous             {
28049c53ac9SJohnathan Mantey                 BMCWEB_LOG_ERROR << "Failed to find '/' in " << chassis;
281daf36e2eSEd Tanous                 continue;
282daf36e2eSEd Tanous             }
28349c53ac9SJohnathan Mantey             chassisName = chassis.substr(lastPos + 1);
28449c53ac9SJohnathan Mantey             if (chassisName == sensorsAsyncResp->chassisId)
2851abe55efSEd Tanous             {
28649c53ac9SJohnathan Mantey                 chassisPath = &chassis;
28749c53ac9SJohnathan Mantey                 break;
288daf36e2eSEd Tanous             }
28949c53ac9SJohnathan Mantey         }
29049c53ac9SJohnathan Mantey         if (chassisPath == nullptr)
2911abe55efSEd Tanous         {
29249c53ac9SJohnathan Mantey             messages::resourceNotFound(sensorsAsyncResp->res, "Chassis",
29349c53ac9SJohnathan Mantey                                        sensorsAsyncResp->chassisId);
29449c53ac9SJohnathan Mantey             return;
2951abe55efSEd Tanous         }
29608777fb0SLewanczyk, Dawid 
29749c53ac9SJohnathan Mantey         const std::string& chassisSubNode = sensorsAsyncResp->chassisSubNode;
29849c53ac9SJohnathan Mantey         if (chassisSubNode == "Power")
29949c53ac9SJohnathan Mantey         {
30049c53ac9SJohnathan Mantey             sensorsAsyncResp->res.jsonValue["@odata.type"] =
30149c53ac9SJohnathan Mantey                 "#Power.v1_5_2.Power";
30249c53ac9SJohnathan Mantey         }
30349c53ac9SJohnathan Mantey         else if (chassisSubNode == "Thermal")
30449c53ac9SJohnathan Mantey         {
30549c53ac9SJohnathan Mantey             sensorsAsyncResp->res.jsonValue["@odata.type"] =
30649c53ac9SJohnathan Mantey                 "#Thermal.v1_4_0.Thermal";
3074f9a2130SJennifer Lee             sensorsAsyncResp->res.jsonValue["Fans"] = nlohmann::json::array();
3084f9a2130SJennifer Lee             sensorsAsyncResp->res.jsonValue["Temperatures"] =
3094f9a2130SJennifer Lee                 nlohmann::json::array();
31049c53ac9SJohnathan Mantey         }
31149c53ac9SJohnathan Mantey         sensorsAsyncResp->res.jsonValue["@odata.id"] =
31249c53ac9SJohnathan Mantey             "/redfish/v1/Chassis/" + sensorsAsyncResp->chassisId + "/" +
31349c53ac9SJohnathan Mantey             chassisSubNode;
31449c53ac9SJohnathan Mantey 
31549c53ac9SJohnathan Mantey         sensorsAsyncResp->res.jsonValue["@odata.context"] =
31649c53ac9SJohnathan Mantey             "/redfish/v1/$metadata#" + chassisSubNode + "." + chassisSubNode;
31749c53ac9SJohnathan Mantey         sensorsAsyncResp->res.jsonValue["Id"] = chassisSubNode;
31849c53ac9SJohnathan Mantey         sensorsAsyncResp->res.jsonValue["Name"] = chassisSubNode;
31949c53ac9SJohnathan Mantey 
3208fb49dd6SShawn McCarney         // Get the list of all sensors for this Chassis element
3218fb49dd6SShawn McCarney         std::string sensorPath = *chassisPath + "/all_sensors";
32255c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
32349c53ac9SJohnathan Mantey             [sensorsAsyncResp, callback{std::move(callback)}](
32449c53ac9SJohnathan Mantey                 const boost::system::error_code ec,
32549c53ac9SJohnathan Mantey                 const std::variant<std::vector<std::string>>&
32649c53ac9SJohnathan Mantey                     variantEndpoints) {
32749c53ac9SJohnathan Mantey                 if (ec)
32849c53ac9SJohnathan Mantey                 {
32949c53ac9SJohnathan Mantey                     if (ec.value() != EBADR)
33049c53ac9SJohnathan Mantey                     {
33149c53ac9SJohnathan Mantey                         messages::internalError(sensorsAsyncResp->res);
33249c53ac9SJohnathan Mantey                         return;
33349c53ac9SJohnathan Mantey                     }
33449c53ac9SJohnathan Mantey                 }
33549c53ac9SJohnathan Mantey                 const std::vector<std::string>* nodeSensorList =
33649c53ac9SJohnathan Mantey                     std::get_if<std::vector<std::string>>(&(variantEndpoints));
33749c53ac9SJohnathan Mantey                 if (nodeSensorList == nullptr)
33849c53ac9SJohnathan Mantey                 {
33949c53ac9SJohnathan Mantey                     messages::resourceNotFound(
34049c53ac9SJohnathan Mantey                         sensorsAsyncResp->res, sensorsAsyncResp->chassisSubNode,
34149c53ac9SJohnathan Mantey                         sensorsAsyncResp->chassisSubNode == "Thermal"
34249c53ac9SJohnathan Mantey                             ? "Temperatures"
34349c53ac9SJohnathan Mantey                             : "Voltages");
34449c53ac9SJohnathan Mantey                     return;
34549c53ac9SJohnathan Mantey                 }
34649c53ac9SJohnathan Mantey                 const std::shared_ptr<boost::container::flat_set<std::string>>
34749c53ac9SJohnathan Mantey                     culledSensorList = std::make_shared<
34849c53ac9SJohnathan Mantey                         boost::container::flat_set<std::string>>();
34949c53ac9SJohnathan Mantey                 reduceSensorList(sensorsAsyncResp, nodeSensorList,
35049c53ac9SJohnathan Mantey                                  culledSensorList);
35149c53ac9SJohnathan Mantey                 callback(culledSensorList);
35249c53ac9SJohnathan Mantey             },
35349c53ac9SJohnathan Mantey             "xyz.openbmc_project.ObjectMapper", sensorPath,
35449c53ac9SJohnathan Mantey             "org.freedesktop.DBus.Properties", "Get",
35549c53ac9SJohnathan Mantey             "xyz.openbmc_project.Association", "endpoints");
35649c53ac9SJohnathan Mantey     };
35749c53ac9SJohnathan Mantey 
35849c53ac9SJohnathan Mantey     // Get the Chassis Collection
35949c53ac9SJohnathan Mantey     crow::connections::systemBus->async_method_call(
36049c53ac9SJohnathan Mantey         respHandler, "xyz.openbmc_project.ObjectMapper",
36149c53ac9SJohnathan Mantey         "/xyz/openbmc_project/object_mapper",
36249c53ac9SJohnathan Mantey         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
36349c53ac9SJohnathan Mantey         "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
36455c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis exit";
36508777fb0SLewanczyk, Dawid }
36608777fb0SLewanczyk, Dawid 
36708777fb0SLewanczyk, Dawid /**
368de629b6eSShawn McCarney  * @brief Finds all DBus object paths that implement ObjectManager.
369de629b6eSShawn McCarney  *
370de629b6eSShawn McCarney  * Creates a mapping from the associated connection name to the object path.
371de629b6eSShawn McCarney  *
372de629b6eSShawn McCarney  * Finds the object paths asynchronously.  Invokes callback when information has
373de629b6eSShawn McCarney  * been obtained.
374de629b6eSShawn McCarney  *
375de629b6eSShawn McCarney  * The callback must have the following signature:
376de629b6eSShawn McCarney  *   @code
3778fb49dd6SShawn McCarney  *   callback(std::shared_ptr<boost::container::flat_map<std::string,
3788fb49dd6SShawn McCarney  *                std::string>> objectMgrPaths)
379de629b6eSShawn McCarney  *   @endcode
380de629b6eSShawn McCarney  *
38149c53ac9SJohnathan Mantey  * @param sensorsAsyncResp Pointer to object holding response data.
382de629b6eSShawn McCarney  * @param callback Callback to invoke when object paths obtained.
383de629b6eSShawn McCarney  */
384de629b6eSShawn McCarney template <typename Callback>
385de629b6eSShawn McCarney void getObjectManagerPaths(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
386de629b6eSShawn McCarney                            Callback&& callback)
387de629b6eSShawn McCarney {
388de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getObjectManagerPaths enter";
389de629b6eSShawn McCarney     const std::array<std::string, 1> interfaces = {
390de629b6eSShawn McCarney         "org.freedesktop.DBus.ObjectManager"};
391de629b6eSShawn McCarney 
392de629b6eSShawn McCarney     // Response handler for GetSubTree DBus method
393de629b6eSShawn McCarney     auto respHandler = [callback{std::move(callback)},
394de629b6eSShawn McCarney                         SensorsAsyncResp](const boost::system::error_code ec,
395de629b6eSShawn McCarney                                           const GetSubTreeType& subtree) {
396de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler enter";
397de629b6eSShawn McCarney         if (ec)
398de629b6eSShawn McCarney         {
399de629b6eSShawn McCarney             messages::internalError(SensorsAsyncResp->res);
400de629b6eSShawn McCarney             BMCWEB_LOG_ERROR << "getObjectManagerPaths respHandler: DBus error "
401de629b6eSShawn McCarney                              << ec;
402de629b6eSShawn McCarney             return;
403de629b6eSShawn McCarney         }
404de629b6eSShawn McCarney 
405de629b6eSShawn McCarney         // Loop over returned object paths
4068fb49dd6SShawn McCarney         std::shared_ptr<boost::container::flat_map<std::string, std::string>>
4078fb49dd6SShawn McCarney             objectMgrPaths = std::make_shared<
4088fb49dd6SShawn McCarney                 boost::container::flat_map<std::string, std::string>>();
409de629b6eSShawn McCarney         for (const std::pair<
410de629b6eSShawn McCarney                  std::string,
411de629b6eSShawn McCarney                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
412de629b6eSShawn McCarney                  object : subtree)
413de629b6eSShawn McCarney         {
414de629b6eSShawn McCarney             // Loop over connections for current object path
415de629b6eSShawn McCarney             const std::string& objectPath = object.first;
416de629b6eSShawn McCarney             for (const std::pair<std::string, std::vector<std::string>>&
417de629b6eSShawn McCarney                      objData : object.second)
418de629b6eSShawn McCarney             {
419de629b6eSShawn McCarney                 // Add mapping from connection to object path
420de629b6eSShawn McCarney                 const std::string& connection = objData.first;
4218fb49dd6SShawn McCarney                 (*objectMgrPaths)[connection] = objectPath;
422de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "Added mapping " << connection << " -> "
423de629b6eSShawn McCarney                                  << objectPath;
424de629b6eSShawn McCarney             }
425de629b6eSShawn McCarney         }
4268fb49dd6SShawn McCarney         callback(objectMgrPaths);
427de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler exit";
428de629b6eSShawn McCarney     };
429de629b6eSShawn McCarney 
430de629b6eSShawn McCarney     // Query mapper for all DBus object paths that implement ObjectManager
431de629b6eSShawn McCarney     crow::connections::systemBus->async_method_call(
432de629b6eSShawn McCarney         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
433de629b6eSShawn McCarney         "/xyz/openbmc_project/object_mapper",
434de629b6eSShawn McCarney         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
435de629b6eSShawn McCarney         interfaces);
436de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getObjectManagerPaths exit";
437de629b6eSShawn McCarney }
438de629b6eSShawn McCarney 
439de629b6eSShawn McCarney /**
440*adc4f0dbSShawn McCarney  * @brief Returns the Redfish State value for the specified inventory item.
441*adc4f0dbSShawn McCarney  * @param inventoryItem D-Bus inventory item associated with a sensor.
442*adc4f0dbSShawn McCarney  * @return State value for inventory item.
44334dd179eSJames Feist  */
444*adc4f0dbSShawn McCarney static std::string getState(const InventoryItem* inventoryItem)
445*adc4f0dbSShawn McCarney {
446*adc4f0dbSShawn McCarney     if ((inventoryItem != nullptr) && !(inventoryItem->isPresent))
447*adc4f0dbSShawn McCarney     {
448*adc4f0dbSShawn McCarney         return "Absent";
449*adc4f0dbSShawn McCarney     }
45034dd179eSJames Feist 
451*adc4f0dbSShawn McCarney     return "Enabled";
452*adc4f0dbSShawn McCarney }
453*adc4f0dbSShawn McCarney 
454*adc4f0dbSShawn McCarney /**
455*adc4f0dbSShawn McCarney  * @brief Returns the Redfish Health value for the specified sensor.
456*adc4f0dbSShawn McCarney  * @param sensorJson Sensor JSON object.
457*adc4f0dbSShawn McCarney  * @param interfacesDict Map of all sensor interfaces.
458*adc4f0dbSShawn McCarney  * @param inventoryItem D-Bus inventory item associated with the sensor.  Will
459*adc4f0dbSShawn McCarney  * be nullptr if no associated inventory item was found.
460*adc4f0dbSShawn McCarney  * @return Health value for sensor.
461*adc4f0dbSShawn McCarney  */
46234dd179eSJames Feist static std::string getHealth(
463*adc4f0dbSShawn McCarney     nlohmann::json& sensorJson,
46434dd179eSJames Feist     const boost::container::flat_map<
46534dd179eSJames Feist         std::string, boost::container::flat_map<std::string, SensorVariant>>&
466*adc4f0dbSShawn McCarney         interfacesDict,
467*adc4f0dbSShawn McCarney     const InventoryItem* inventoryItem)
46834dd179eSJames Feist {
469*adc4f0dbSShawn McCarney     // Get current health value (if any) in the sensor JSON object.  Some JSON
470*adc4f0dbSShawn McCarney     // objects contain multiple sensors (such as PowerSupplies).  We want to set
471*adc4f0dbSShawn McCarney     // the overall health to be the most severe of any of the sensors.
472*adc4f0dbSShawn McCarney     std::string currentHealth;
473*adc4f0dbSShawn McCarney     auto statusIt = sensorJson.find("Status");
474*adc4f0dbSShawn McCarney     if (statusIt != sensorJson.end())
475*adc4f0dbSShawn McCarney     {
476*adc4f0dbSShawn McCarney         auto healthIt = statusIt->find("Health");
477*adc4f0dbSShawn McCarney         if (healthIt != statusIt->end())
478*adc4f0dbSShawn McCarney         {
479*adc4f0dbSShawn McCarney             std::string* health = healthIt->get_ptr<std::string*>();
480*adc4f0dbSShawn McCarney             if (health != nullptr)
481*adc4f0dbSShawn McCarney             {
482*adc4f0dbSShawn McCarney                 currentHealth = *health;
483*adc4f0dbSShawn McCarney             }
484*adc4f0dbSShawn McCarney         }
485*adc4f0dbSShawn McCarney     }
486*adc4f0dbSShawn McCarney 
487*adc4f0dbSShawn McCarney     // If current health in JSON object is already Critical, return that.  This
488*adc4f0dbSShawn McCarney     // should override the sensor health, which might be less severe.
489*adc4f0dbSShawn McCarney     if (currentHealth == "Critical")
490*adc4f0dbSShawn McCarney     {
491*adc4f0dbSShawn McCarney         return "Critical";
492*adc4f0dbSShawn McCarney     }
493*adc4f0dbSShawn McCarney 
494*adc4f0dbSShawn McCarney     // Check if sensor has critical threshold alarm
49534dd179eSJames Feist     auto criticalThresholdIt =
49634dd179eSJames Feist         interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Critical");
49734dd179eSJames Feist     if (criticalThresholdIt != interfacesDict.end())
49834dd179eSJames Feist     {
49934dd179eSJames Feist         auto thresholdHighIt =
50034dd179eSJames Feist             criticalThresholdIt->second.find("CriticalAlarmHigh");
50134dd179eSJames Feist         auto thresholdLowIt =
50234dd179eSJames Feist             criticalThresholdIt->second.find("CriticalAlarmLow");
50334dd179eSJames Feist         if (thresholdHighIt != criticalThresholdIt->second.end())
50434dd179eSJames Feist         {
50534dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdHighIt->second);
50634dd179eSJames Feist             if (asserted == nullptr)
50734dd179eSJames Feist             {
50834dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
50934dd179eSJames Feist             }
51034dd179eSJames Feist             else if (*asserted)
51134dd179eSJames Feist             {
51234dd179eSJames Feist                 return "Critical";
51334dd179eSJames Feist             }
51434dd179eSJames Feist         }
51534dd179eSJames Feist         if (thresholdLowIt != criticalThresholdIt->second.end())
51634dd179eSJames Feist         {
51734dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdLowIt->second);
51834dd179eSJames Feist             if (asserted == nullptr)
51934dd179eSJames Feist             {
52034dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
52134dd179eSJames Feist             }
52234dd179eSJames Feist             else if (*asserted)
52334dd179eSJames Feist             {
52434dd179eSJames Feist                 return "Critical";
52534dd179eSJames Feist             }
52634dd179eSJames Feist         }
52734dd179eSJames Feist     }
52834dd179eSJames Feist 
529*adc4f0dbSShawn McCarney     // Check if associated inventory item is not functional
530*adc4f0dbSShawn McCarney     if ((inventoryItem != nullptr) && !(inventoryItem->isFunctional))
531*adc4f0dbSShawn McCarney     {
532*adc4f0dbSShawn McCarney         return "Critical";
533*adc4f0dbSShawn McCarney     }
534*adc4f0dbSShawn McCarney 
535*adc4f0dbSShawn McCarney     // If current health in JSON object is already Warning, return that.  This
536*adc4f0dbSShawn McCarney     // should override the sensor status, which might be less severe.
537*adc4f0dbSShawn McCarney     if (currentHealth == "Warning")
538*adc4f0dbSShawn McCarney     {
539*adc4f0dbSShawn McCarney         return "Warning";
540*adc4f0dbSShawn McCarney     }
541*adc4f0dbSShawn McCarney 
542*adc4f0dbSShawn McCarney     // Check if sensor has warning threshold alarm
54334dd179eSJames Feist     auto warningThresholdIt =
54434dd179eSJames Feist         interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Warning");
54534dd179eSJames Feist     if (warningThresholdIt != interfacesDict.end())
54634dd179eSJames Feist     {
54734dd179eSJames Feist         auto thresholdHighIt =
54834dd179eSJames Feist             warningThresholdIt->second.find("WarningAlarmHigh");
54934dd179eSJames Feist         auto thresholdLowIt =
55034dd179eSJames Feist             warningThresholdIt->second.find("WarningAlarmLow");
55134dd179eSJames Feist         if (thresholdHighIt != warningThresholdIt->second.end())
55234dd179eSJames Feist         {
55334dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdHighIt->second);
55434dd179eSJames Feist             if (asserted == nullptr)
55534dd179eSJames Feist             {
55634dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
55734dd179eSJames Feist             }
55834dd179eSJames Feist             else if (*asserted)
55934dd179eSJames Feist             {
56034dd179eSJames Feist                 return "Warning";
56134dd179eSJames Feist             }
56234dd179eSJames Feist         }
56334dd179eSJames Feist         if (thresholdLowIt != warningThresholdIt->second.end())
56434dd179eSJames Feist         {
56534dd179eSJames Feist             const bool* asserted = std::get_if<bool>(&thresholdLowIt->second);
56634dd179eSJames Feist             if (asserted == nullptr)
56734dd179eSJames Feist             {
56834dd179eSJames Feist                 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
56934dd179eSJames Feist             }
57034dd179eSJames Feist             else if (*asserted)
57134dd179eSJames Feist             {
57234dd179eSJames Feist                 return "Warning";
57334dd179eSJames Feist             }
57434dd179eSJames Feist         }
57534dd179eSJames Feist     }
576*adc4f0dbSShawn McCarney 
57734dd179eSJames Feist     return "OK";
57834dd179eSJames Feist }
57934dd179eSJames Feist 
58034dd179eSJames Feist /**
58108777fb0SLewanczyk, Dawid  * @brief Builds a json sensor representation of a sensor.
58208777fb0SLewanczyk, Dawid  * @param sensorName  The name of the sensor to be built
583274fad5aSGunnar Mills  * @param sensorType  The type (temperature, fan_tach, etc) of the sensor to
58408777fb0SLewanczyk, Dawid  * build
58508777fb0SLewanczyk, Dawid  * @param interfacesDict  A dictionary of the interfaces and properties of said
58608777fb0SLewanczyk, Dawid  * interfaces to be built from
58708777fb0SLewanczyk, Dawid  * @param sensor_json  The json object to fill
588*adc4f0dbSShawn McCarney  * @param inventoryItem D-Bus inventory item associated with the sensor.  Will
589*adc4f0dbSShawn McCarney  * be nullptr if no associated inventory item was found.
59008777fb0SLewanczyk, Dawid  */
59108777fb0SLewanczyk, Dawid void objectInterfacesToJson(
59208777fb0SLewanczyk, Dawid     const std::string& sensorName, const std::string& sensorType,
59308777fb0SLewanczyk, Dawid     const boost::container::flat_map<
594aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>&
59508777fb0SLewanczyk, Dawid         interfacesDict,
596*adc4f0dbSShawn McCarney     nlohmann::json& sensor_json, InventoryItem* inventoryItem)
5971abe55efSEd Tanous {
59808777fb0SLewanczyk, Dawid     // We need a value interface before we can do anything with it
59955c7b7a2SEd Tanous     auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
6001abe55efSEd Tanous     if (valueIt == interfacesDict.end())
6011abe55efSEd Tanous     {
60255c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface";
60308777fb0SLewanczyk, Dawid         return;
60408777fb0SLewanczyk, Dawid     }
60508777fb0SLewanczyk, Dawid 
60608777fb0SLewanczyk, Dawid     // Assume values exist as is (10^0 == 1) if no scale exists
60708777fb0SLewanczyk, Dawid     int64_t scaleMultiplier = 0;
60808777fb0SLewanczyk, Dawid 
60955c7b7a2SEd Tanous     auto scaleIt = valueIt->second.find("Scale");
61008777fb0SLewanczyk, Dawid     // If a scale exists, pull value as int64, and use the scaling.
6111abe55efSEd Tanous     if (scaleIt != valueIt->second.end())
6121abe55efSEd Tanous     {
613abf2add6SEd Tanous         const int64_t* int64Value = std::get_if<int64_t>(&scaleIt->second);
6141abe55efSEd Tanous         if (int64Value != nullptr)
6151abe55efSEd Tanous         {
61608777fb0SLewanczyk, Dawid             scaleMultiplier = *int64Value;
61708777fb0SLewanczyk, Dawid         }
61808777fb0SLewanczyk, Dawid     }
61908777fb0SLewanczyk, Dawid 
620*adc4f0dbSShawn McCarney     // Set MemberId and Name for non-power sensors.  For PowerSupplies and
621*adc4f0dbSShawn McCarney     // PowerControl, those properties have more general values because multiple
622*adc4f0dbSShawn McCarney     // sensors can be stored in the same JSON object.
623*adc4f0dbSShawn McCarney     if (sensorType != "power")
624*adc4f0dbSShawn McCarney     {
62508777fb0SLewanczyk, Dawid         sensor_json["MemberId"] = sensorName;
626e742b6ccSEd Tanous         sensor_json["Name"] = boost::replace_all_copy(sensorName, "_", " ");
627*adc4f0dbSShawn McCarney     }
628e742b6ccSEd Tanous 
629*adc4f0dbSShawn McCarney     sensor_json["Status"]["State"] = getState(inventoryItem);
630*adc4f0dbSShawn McCarney     sensor_json["Status"]["Health"] =
631*adc4f0dbSShawn McCarney         getHealth(sensor_json, interfacesDict, inventoryItem);
63208777fb0SLewanczyk, Dawid 
63308777fb0SLewanczyk, Dawid     // Parameter to set to override the type we get from dbus, and force it to
63408777fb0SLewanczyk, Dawid     // int, regardless of what is available.  This is used for schemas like fan,
63508777fb0SLewanczyk, Dawid     // that require integers, not floats.
63608777fb0SLewanczyk, Dawid     bool forceToInt = false;
63708777fb0SLewanczyk, Dawid 
63808777fb0SLewanczyk, Dawid     const char* unit = "Reading";
6391abe55efSEd Tanous     if (sensorType == "temperature")
6401abe55efSEd Tanous     {
64108777fb0SLewanczyk, Dawid         unit = "ReadingCelsius";
6427885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature";
64308777fb0SLewanczyk, Dawid         // TODO(ed) Documentation says that path should be type fan_tach,
64408777fb0SLewanczyk, Dawid         // implementation seems to implement fan
6451abe55efSEd Tanous     }
6461abe55efSEd Tanous     else if (sensorType == "fan" || sensorType == "fan_tach")
6471abe55efSEd Tanous     {
64808777fb0SLewanczyk, Dawid         unit = "Reading";
64908777fb0SLewanczyk, Dawid         sensor_json["ReadingUnits"] = "RPM";
6507885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
65108777fb0SLewanczyk, Dawid         forceToInt = true;
6521abe55efSEd Tanous     }
6536f6d0d32SEd Tanous     else if (sensorType == "fan_pwm")
6546f6d0d32SEd Tanous     {
6556f6d0d32SEd Tanous         unit = "Reading";
6566f6d0d32SEd Tanous         sensor_json["ReadingUnits"] = "Percent";
6576f6d0d32SEd Tanous         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
6586f6d0d32SEd Tanous         forceToInt = true;
6596f6d0d32SEd Tanous     }
6601abe55efSEd Tanous     else if (sensorType == "voltage")
6611abe55efSEd Tanous     {
66208777fb0SLewanczyk, Dawid         unit = "ReadingVolts";
6637885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage";
6641abe55efSEd Tanous     }
6652474adfaSEd Tanous     else if (sensorType == "power")
6662474adfaSEd Tanous     {
66749c53ac9SJohnathan Mantey         std::string sensorNameLower =
66849c53ac9SJohnathan Mantey             boost::algorithm::to_lower_copy(sensorName);
66949c53ac9SJohnathan Mantey 
670028f7ebcSEddie James         if (!sensorName.compare("total_power"))
671028f7ebcSEddie James         {
6727ab06f49SGunnar Mills             sensor_json["@odata.type"] = "#Power.v1_0_0.PowerControl";
6737ab06f49SGunnar Mills             // Put multiple "sensors" into a single PowerControl, so have
6747ab06f49SGunnar Mills             // generic names for MemberId and Name. Follows Redfish mockup.
6757ab06f49SGunnar Mills             sensor_json["MemberId"] = "0";
6767ab06f49SGunnar Mills             sensor_json["Name"] = "Chassis Power Control";
677028f7ebcSEddie James             unit = "PowerConsumedWatts";
678028f7ebcSEddie James         }
679028f7ebcSEddie James         else if (sensorNameLower.find("input") != std::string::npos)
68049c53ac9SJohnathan Mantey         {
68149c53ac9SJohnathan Mantey             unit = "PowerInputWatts";
68249c53ac9SJohnathan Mantey         }
68349c53ac9SJohnathan Mantey         else
68449c53ac9SJohnathan Mantey         {
68549c53ac9SJohnathan Mantey             unit = "PowerOutputWatts";
68649c53ac9SJohnathan Mantey         }
6872474adfaSEd Tanous     }
6881abe55efSEd Tanous     else
6891abe55efSEd Tanous     {
69055c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
69108777fb0SLewanczyk, Dawid         return;
69208777fb0SLewanczyk, Dawid     }
69308777fb0SLewanczyk, Dawid     // Map of dbus interface name, dbus property name and redfish property_name
69408777fb0SLewanczyk, Dawid     std::vector<std::tuple<const char*, const char*, const char*>> properties;
69508777fb0SLewanczyk, Dawid     properties.reserve(7);
69608777fb0SLewanczyk, Dawid 
69708777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
698de629b6eSShawn McCarney 
699*adc4f0dbSShawn McCarney     if (sensorType != "power")
700de629b6eSShawn McCarney     {
70108777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
70208777fb0SLewanczyk, Dawid                                 "WarningHigh", "UpperThresholdNonCritical");
70308777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
70408777fb0SLewanczyk, Dawid                                 "WarningLow", "LowerThresholdNonCritical");
70508777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
70608777fb0SLewanczyk, Dawid                                 "CriticalHigh", "UpperThresholdCritical");
70708777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
70808777fb0SLewanczyk, Dawid                                 "CriticalLow", "LowerThresholdCritical");
709de629b6eSShawn McCarney     }
71008777fb0SLewanczyk, Dawid 
7112474adfaSEd Tanous     // TODO Need to get UpperThresholdFatal and LowerThresholdFatal
7122474adfaSEd Tanous 
7131abe55efSEd Tanous     if (sensorType == "temperature")
7141abe55efSEd Tanous     {
71508777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
71608777fb0SLewanczyk, Dawid                                 "MinReadingRangeTemp");
71708777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
71808777fb0SLewanczyk, Dawid                                 "MaxReadingRangeTemp");
7191abe55efSEd Tanous     }
720*adc4f0dbSShawn McCarney     else if (sensorType != "power")
7211abe55efSEd Tanous     {
72208777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
72308777fb0SLewanczyk, Dawid                                 "MinReadingRange");
72408777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
72508777fb0SLewanczyk, Dawid                                 "MaxReadingRange");
72608777fb0SLewanczyk, Dawid     }
72708777fb0SLewanczyk, Dawid 
72808777fb0SLewanczyk, Dawid     for (const std::tuple<const char*, const char*, const char*>& p :
7291abe55efSEd Tanous          properties)
7301abe55efSEd Tanous     {
73108777fb0SLewanczyk, Dawid         auto interfaceProperties = interfacesDict.find(std::get<0>(p));
7321abe55efSEd Tanous         if (interfaceProperties != interfacesDict.end())
7331abe55efSEd Tanous         {
734b01bf299SEd Tanous             auto valueIt = interfaceProperties->second.find(std::get<1>(p));
735b01bf299SEd Tanous             if (valueIt != interfaceProperties->second.end())
7361abe55efSEd Tanous             {
737b01bf299SEd Tanous                 const SensorVariant& valueVariant = valueIt->second;
738b01bf299SEd Tanous                 nlohmann::json& valueIt = sensor_json[std::get<2>(p)];
73908777fb0SLewanczyk, Dawid                 // Attempt to pull the int64 directly
740abf2add6SEd Tanous                 const int64_t* int64Value = std::get_if<int64_t>(&valueVariant);
74108777fb0SLewanczyk, Dawid 
742abf2add6SEd Tanous                 const double* doubleValue = std::get_if<double>(&valueVariant);
743028f7ebcSEddie James                 const uint32_t* uValue = std::get_if<uint32_t>(&valueVariant);
7446f6d0d32SEd Tanous                 double temp = 0.0;
7456f6d0d32SEd Tanous                 if (int64Value != nullptr)
7461abe55efSEd Tanous                 {
7476f6d0d32SEd Tanous                     temp = *int64Value;
7486f6d0d32SEd Tanous                 }
7496f6d0d32SEd Tanous                 else if (doubleValue != nullptr)
7501abe55efSEd Tanous                 {
7516f6d0d32SEd Tanous                     temp = *doubleValue;
7521abe55efSEd Tanous                 }
753028f7ebcSEddie James                 else if (uValue != nullptr)
754028f7ebcSEddie James                 {
755028f7ebcSEddie James                     temp = *uValue;
756028f7ebcSEddie James                 }
7571abe55efSEd Tanous                 else
7581abe55efSEd Tanous                 {
7596f6d0d32SEd Tanous                     BMCWEB_LOG_ERROR
7606f6d0d32SEd Tanous                         << "Got value interface that wasn't int or double";
7616f6d0d32SEd Tanous                     continue;
76208777fb0SLewanczyk, Dawid                 }
7636f6d0d32SEd Tanous                 temp = temp * std::pow(10, scaleMultiplier);
7646f6d0d32SEd Tanous                 if (forceToInt)
7656f6d0d32SEd Tanous                 {
766b01bf299SEd Tanous                     valueIt = static_cast<int64_t>(temp);
7676f6d0d32SEd Tanous                 }
7686f6d0d32SEd Tanous                 else
7696f6d0d32SEd Tanous                 {
770b01bf299SEd Tanous                     valueIt = temp;
77108777fb0SLewanczyk, Dawid                 }
77208777fb0SLewanczyk, Dawid             }
77308777fb0SLewanczyk, Dawid         }
77408777fb0SLewanczyk, Dawid     }
77555c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
77608777fb0SLewanczyk, Dawid }
77708777fb0SLewanczyk, Dawid 
7788bd25ccdSJames Feist static void
7798bd25ccdSJames Feist     populateFanRedundancy(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp)
7808bd25ccdSJames Feist {
7818bd25ccdSJames Feist     crow::connections::systemBus->async_method_call(
7828bd25ccdSJames Feist         [sensorsAsyncResp](const boost::system::error_code ec,
7838bd25ccdSJames Feist                            const GetSubTreeType& resp) {
7848bd25ccdSJames Feist             if (ec)
7858bd25ccdSJames Feist             {
7868bd25ccdSJames Feist                 return; // don't have to have this interface
7878bd25ccdSJames Feist             }
788e278c18fSEd Tanous             for (const std::pair<std::string,
789e278c18fSEd Tanous                                  std::vector<std::pair<
790e278c18fSEd Tanous                                      std::string, std::vector<std::string>>>>&
791e278c18fSEd Tanous                      pathPair : resp)
7928bd25ccdSJames Feist             {
793e278c18fSEd Tanous                 const std::string& path = pathPair.first;
794e278c18fSEd Tanous                 const std::vector<
795e278c18fSEd Tanous                     std::pair<std::string, std::vector<std::string>>>& objDict =
796e278c18fSEd Tanous                     pathPair.second;
7978bd25ccdSJames Feist                 if (objDict.empty())
7988bd25ccdSJames Feist                 {
7998bd25ccdSJames Feist                     continue; // this should be impossible
8008bd25ccdSJames Feist                 }
8018bd25ccdSJames Feist 
8028bd25ccdSJames Feist                 const std::string& owner = objDict.begin()->first;
8038bd25ccdSJames Feist                 crow::connections::systemBus->async_method_call(
8048bd25ccdSJames Feist                     [path, owner,
8058bd25ccdSJames Feist                      sensorsAsyncResp](const boost::system::error_code ec,
8068bd25ccdSJames Feist                                        std::variant<std::vector<std::string>>
8078bd25ccdSJames Feist                                            variantEndpoints) {
8088bd25ccdSJames Feist                         if (ec)
8098bd25ccdSJames Feist                         {
8108bd25ccdSJames Feist                             return; // if they don't have an association we
8118bd25ccdSJames Feist                                     // can't tell what chassis is
8128bd25ccdSJames Feist                         }
8138bd25ccdSJames Feist                         // verify part of the right chassis
8148bd25ccdSJames Feist                         auto endpoints = std::get_if<std::vector<std::string>>(
8158bd25ccdSJames Feist                             &variantEndpoints);
8168bd25ccdSJames Feist 
8178bd25ccdSJames Feist                         if (endpoints == nullptr)
8188bd25ccdSJames Feist                         {
8198bd25ccdSJames Feist                             BMCWEB_LOG_ERROR << "Invalid association interface";
8208bd25ccdSJames Feist                             messages::internalError(sensorsAsyncResp->res);
8218bd25ccdSJames Feist                             return;
8228bd25ccdSJames Feist                         }
8238bd25ccdSJames Feist 
8248bd25ccdSJames Feist                         auto found = std::find_if(
8258bd25ccdSJames Feist                             endpoints->begin(), endpoints->end(),
8268bd25ccdSJames Feist                             [sensorsAsyncResp](const std::string& entry) {
8278bd25ccdSJames Feist                                 return entry.find(
8288bd25ccdSJames Feist                                            sensorsAsyncResp->chassisId) !=
8298bd25ccdSJames Feist                                        std::string::npos;
8308bd25ccdSJames Feist                             });
8318bd25ccdSJames Feist 
8328bd25ccdSJames Feist                         if (found == endpoints->end())
8338bd25ccdSJames Feist                         {
8348bd25ccdSJames Feist                             return;
8358bd25ccdSJames Feist                         }
8368bd25ccdSJames Feist                         crow::connections::systemBus->async_method_call(
8378bd25ccdSJames Feist                             [path, sensorsAsyncResp](
8388bd25ccdSJames Feist                                 const boost::system::error_code ec,
8398bd25ccdSJames Feist                                 const boost::container::flat_map<
8408bd25ccdSJames Feist                                     std::string,
8418bd25ccdSJames Feist                                     std::variant<uint8_t,
8428bd25ccdSJames Feist                                                  std::vector<std::string>,
8438bd25ccdSJames Feist                                                  std::string>>& ret) {
8448bd25ccdSJames Feist                                 if (ec)
8458bd25ccdSJames Feist                                 {
8468bd25ccdSJames Feist                                     return; // don't have to have this
8478bd25ccdSJames Feist                                             // interface
8488bd25ccdSJames Feist                                 }
8498bd25ccdSJames Feist                                 auto findFailures = ret.find("AllowedFailures");
8508bd25ccdSJames Feist                                 auto findCollection = ret.find("Collection");
8518bd25ccdSJames Feist                                 auto findStatus = ret.find("Status");
8528bd25ccdSJames Feist 
8538bd25ccdSJames Feist                                 if (findFailures == ret.end() ||
8548bd25ccdSJames Feist                                     findCollection == ret.end() ||
8558bd25ccdSJames Feist                                     findStatus == ret.end())
8568bd25ccdSJames Feist                                 {
8578bd25ccdSJames Feist                                     BMCWEB_LOG_ERROR
8588bd25ccdSJames Feist                                         << "Invalid redundancy interface";
8598bd25ccdSJames Feist                                     messages::internalError(
8608bd25ccdSJames Feist                                         sensorsAsyncResp->res);
8618bd25ccdSJames Feist                                     return;
8628bd25ccdSJames Feist                                 }
8638bd25ccdSJames Feist 
8648bd25ccdSJames Feist                                 auto allowedFailures = std::get_if<uint8_t>(
8658bd25ccdSJames Feist                                     &(findFailures->second));
8668bd25ccdSJames Feist                                 auto collection =
8678bd25ccdSJames Feist                                     std::get_if<std::vector<std::string>>(
8688bd25ccdSJames Feist                                         &(findCollection->second));
8698bd25ccdSJames Feist                                 auto status = std::get_if<std::string>(
8708bd25ccdSJames Feist                                     &(findStatus->second));
8718bd25ccdSJames Feist 
8728bd25ccdSJames Feist                                 if (allowedFailures == nullptr ||
8738bd25ccdSJames Feist                                     collection == nullptr || status == nullptr)
8748bd25ccdSJames Feist                                 {
8758bd25ccdSJames Feist 
8768bd25ccdSJames Feist                                     BMCWEB_LOG_ERROR
8778bd25ccdSJames Feist                                         << "Invalid redundancy interface "
8788bd25ccdSJames Feist                                            "types";
8798bd25ccdSJames Feist                                     messages::internalError(
8808bd25ccdSJames Feist                                         sensorsAsyncResp->res);
8818bd25ccdSJames Feist                                     return;
8828bd25ccdSJames Feist                                 }
8838bd25ccdSJames Feist                                 size_t lastSlash = path.rfind("/");
8848bd25ccdSJames Feist                                 if (lastSlash == std::string::npos)
8858bd25ccdSJames Feist                                 {
8868bd25ccdSJames Feist                                     // this should be impossible
8878bd25ccdSJames Feist                                     messages::internalError(
8888bd25ccdSJames Feist                                         sensorsAsyncResp->res);
8898bd25ccdSJames Feist                                     return;
8908bd25ccdSJames Feist                                 }
8918bd25ccdSJames Feist                                 std::string name = path.substr(lastSlash + 1);
8928bd25ccdSJames Feist                                 std::replace(name.begin(), name.end(), '_',
8938bd25ccdSJames Feist                                              ' ');
8948bd25ccdSJames Feist 
8958bd25ccdSJames Feist                                 std::string health;
8968bd25ccdSJames Feist 
8978bd25ccdSJames Feist                                 if (boost::ends_with(*status, "Full"))
8988bd25ccdSJames Feist                                 {
8998bd25ccdSJames Feist                                     health = "OK";
9008bd25ccdSJames Feist                                 }
9018bd25ccdSJames Feist                                 else if (boost::ends_with(*status, "Degraded"))
9028bd25ccdSJames Feist                                 {
9038bd25ccdSJames Feist                                     health = "Warning";
9048bd25ccdSJames Feist                                 }
9058bd25ccdSJames Feist                                 else
9068bd25ccdSJames Feist                                 {
9078bd25ccdSJames Feist                                     health = "Critical";
9088bd25ccdSJames Feist                                 }
9098bd25ccdSJames Feist                                 std::vector<nlohmann::json> redfishCollection;
9108bd25ccdSJames Feist                                 const auto& fanRedfish =
9118bd25ccdSJames Feist                                     sensorsAsyncResp->res.jsonValue["Fans"];
9128bd25ccdSJames Feist                                 for (const std::string& item : *collection)
9138bd25ccdSJames Feist                                 {
9148bd25ccdSJames Feist                                     lastSlash = item.rfind("/");
9158bd25ccdSJames Feist                                     // make a copy as collection is const
9168bd25ccdSJames Feist                                     std::string itemName =
9178bd25ccdSJames Feist                                         item.substr(lastSlash + 1);
9188bd25ccdSJames Feist                                     /*
9198bd25ccdSJames Feist                                     todo(ed): merge patch that fixes the names
9208bd25ccdSJames Feist                                     std::replace(itemName.begin(),
9218bd25ccdSJames Feist                                                  itemName.end(), '_', ' ');*/
9228bd25ccdSJames Feist                                     auto schemaItem = std::find_if(
9238bd25ccdSJames Feist                                         fanRedfish.begin(), fanRedfish.end(),
9248bd25ccdSJames Feist                                         [itemName](const nlohmann::json& fan) {
9258bd25ccdSJames Feist                                             return fan["MemberId"] == itemName;
9268bd25ccdSJames Feist                                         });
9278bd25ccdSJames Feist                                     if (schemaItem != fanRedfish.end())
9288bd25ccdSJames Feist                                     {
9298bd25ccdSJames Feist                                         redfishCollection.push_back(
9308bd25ccdSJames Feist                                             {{"@odata.id",
9318bd25ccdSJames Feist                                               (*schemaItem)["@odata.id"]}});
9328bd25ccdSJames Feist                                     }
9338bd25ccdSJames Feist                                     else
9348bd25ccdSJames Feist                                     {
9358bd25ccdSJames Feist                                         BMCWEB_LOG_ERROR
9368bd25ccdSJames Feist                                             << "failed to find fan in schema";
9378bd25ccdSJames Feist                                         messages::internalError(
9388bd25ccdSJames Feist                                             sensorsAsyncResp->res);
9398bd25ccdSJames Feist                                         return;
9408bd25ccdSJames Feist                                     }
9418bd25ccdSJames Feist                                 }
9428bd25ccdSJames Feist 
9438bd25ccdSJames Feist                                 auto& resp = sensorsAsyncResp->res
9448bd25ccdSJames Feist                                                  .jsonValue["Redundancy"];
9458bd25ccdSJames Feist                                 resp.push_back(
9468bd25ccdSJames Feist                                     {{"@odata.id",
9478bd25ccdSJames Feist                                       "/refish/v1/Chassis/" +
9488bd25ccdSJames Feist                                           sensorsAsyncResp->chassisId + "/" +
9498bd25ccdSJames Feist                                           sensorsAsyncResp->chassisSubNode +
9508bd25ccdSJames Feist                                           "#/Redundancy/" +
9518bd25ccdSJames Feist                                           std::to_string(resp.size())},
9528bd25ccdSJames Feist                                      {"@odata.type",
9538bd25ccdSJames Feist                                       "#Redundancy.v1_3_2.Redundancy"},
9548bd25ccdSJames Feist                                      {"MinNumNeeded",
9558bd25ccdSJames Feist                                       collection->size() - *allowedFailures},
9568bd25ccdSJames Feist                                      {"MemberId", name},
9578bd25ccdSJames Feist                                      {"Mode", "N+m"},
9588bd25ccdSJames Feist                                      {"Name", name},
9598bd25ccdSJames Feist                                      {"RedundancySet", redfishCollection},
9608bd25ccdSJames Feist                                      {"Status",
9618bd25ccdSJames Feist                                       {{"Health", health},
9628bd25ccdSJames Feist                                        {"State", "Enabled"}}}});
9638bd25ccdSJames Feist                             },
9648bd25ccdSJames Feist                             owner, path, "org.freedesktop.DBus.Properties",
9658bd25ccdSJames Feist                             "GetAll",
9668bd25ccdSJames Feist                             "xyz.openbmc_project.Control.FanRedundancy");
9678bd25ccdSJames Feist                     },
96802e92e32SJames Feist                     "xyz.openbmc_project.ObjectMapper", path + "/chassis",
9698bd25ccdSJames Feist                     "org.freedesktop.DBus.Properties", "Get",
9708bd25ccdSJames Feist                     "xyz.openbmc_project.Association", "endpoints");
9718bd25ccdSJames Feist             }
9728bd25ccdSJames Feist         },
9738bd25ccdSJames Feist         "xyz.openbmc_project.ObjectMapper",
9748bd25ccdSJames Feist         "/xyz/openbmc_project/object_mapper",
9758bd25ccdSJames Feist         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
9768bd25ccdSJames Feist         "/xyz/openbmc_project/control", 2,
9778bd25ccdSJames Feist         std::array<const char*, 1>{
9788bd25ccdSJames Feist             "xyz.openbmc_project.Control.FanRedundancy"});
9798bd25ccdSJames Feist }
9808bd25ccdSJames Feist 
98149c53ac9SJohnathan Mantey void sortJSONResponse(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
98249c53ac9SJohnathan Mantey {
98349c53ac9SJohnathan Mantey     nlohmann::json& response = SensorsAsyncResp->res.jsonValue;
98449c53ac9SJohnathan Mantey     std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
98549c53ac9SJohnathan Mantey     if (SensorsAsyncResp->chassisSubNode == "Power")
98649c53ac9SJohnathan Mantey     {
98749c53ac9SJohnathan Mantey         sensorHeaders = {"Voltages", "PowerSupplies"};
98849c53ac9SJohnathan Mantey     }
98949c53ac9SJohnathan Mantey     for (const std::string& sensorGroup : sensorHeaders)
99049c53ac9SJohnathan Mantey     {
99149c53ac9SJohnathan Mantey         nlohmann::json::iterator entry = response.find(sensorGroup);
99249c53ac9SJohnathan Mantey         if (entry != response.end())
99349c53ac9SJohnathan Mantey         {
99449c53ac9SJohnathan Mantey             std::sort(entry->begin(), entry->end(),
99549c53ac9SJohnathan Mantey                       [](nlohmann::json& c1, nlohmann::json& c2) {
99649c53ac9SJohnathan Mantey                           return c1["Name"] < c2["Name"];
99749c53ac9SJohnathan Mantey                       });
99849c53ac9SJohnathan Mantey 
99949c53ac9SJohnathan Mantey             // add the index counts to the end of each entry
100049c53ac9SJohnathan Mantey             size_t count = 0;
100149c53ac9SJohnathan Mantey             for (nlohmann::json& sensorJson : *entry)
100249c53ac9SJohnathan Mantey             {
100349c53ac9SJohnathan Mantey                 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
100449c53ac9SJohnathan Mantey                 if (odata == sensorJson.end())
100549c53ac9SJohnathan Mantey                 {
100649c53ac9SJohnathan Mantey                     continue;
100749c53ac9SJohnathan Mantey                 }
100849c53ac9SJohnathan Mantey                 std::string* value = odata->get_ptr<std::string*>();
100949c53ac9SJohnathan Mantey                 if (value != nullptr)
101049c53ac9SJohnathan Mantey                 {
101149c53ac9SJohnathan Mantey                     *value += std::to_string(count);
101249c53ac9SJohnathan Mantey                     count++;
101349c53ac9SJohnathan Mantey                 }
101449c53ac9SJohnathan Mantey             }
101549c53ac9SJohnathan Mantey         }
101649c53ac9SJohnathan Mantey     }
101749c53ac9SJohnathan Mantey }
101849c53ac9SJohnathan Mantey 
101908777fb0SLewanczyk, Dawid /**
1020*adc4f0dbSShawn McCarney  * @brief Finds the inventory item with the specified object path.
1021*adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
1022*adc4f0dbSShawn McCarney  * @param invItemObjPath D-Bus object path of inventory item.
1023*adc4f0dbSShawn McCarney  * @return Inventory item within vector, or nullptr if no match found.
10248fb49dd6SShawn McCarney  */
1025*adc4f0dbSShawn McCarney static InventoryItem* findInventoryItem(
1026*adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1027*adc4f0dbSShawn McCarney     const std::string& invItemObjPath)
10288fb49dd6SShawn McCarney {
1029*adc4f0dbSShawn McCarney     for (InventoryItem& inventoryItem : *inventoryItems)
10308fb49dd6SShawn McCarney     {
1031*adc4f0dbSShawn McCarney         if (inventoryItem.objectPath == invItemObjPath)
10328fb49dd6SShawn McCarney         {
1033*adc4f0dbSShawn McCarney             return &inventoryItem;
10348fb49dd6SShawn McCarney         }
10358fb49dd6SShawn McCarney     }
10368fb49dd6SShawn McCarney     return nullptr;
10378fb49dd6SShawn McCarney }
10388fb49dd6SShawn McCarney 
10398fb49dd6SShawn McCarney /**
1040*adc4f0dbSShawn McCarney  * @brief Finds the inventory item associated with the specified sensor.
1041*adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
1042*adc4f0dbSShawn McCarney  * @param sensorObjPath D-Bus object path of sensor.
1043*adc4f0dbSShawn McCarney  * @return Inventory item within vector, or nullptr if no match found.
10448fb49dd6SShawn McCarney  */
1045*adc4f0dbSShawn McCarney static InventoryItem* findInventoryItemForSensor(
1046*adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1047*adc4f0dbSShawn McCarney     const std::string& sensorObjPath)
1048*adc4f0dbSShawn McCarney {
1049*adc4f0dbSShawn McCarney     for (InventoryItem& inventoryItem : *inventoryItems)
1050*adc4f0dbSShawn McCarney     {
1051*adc4f0dbSShawn McCarney         if (inventoryItem.sensors.count(sensorObjPath) > 0)
1052*adc4f0dbSShawn McCarney         {
1053*adc4f0dbSShawn McCarney             return &inventoryItem;
1054*adc4f0dbSShawn McCarney         }
1055*adc4f0dbSShawn McCarney     }
1056*adc4f0dbSShawn McCarney     return nullptr;
1057*adc4f0dbSShawn McCarney }
1058*adc4f0dbSShawn McCarney 
1059*adc4f0dbSShawn McCarney /**
1060*adc4f0dbSShawn McCarney  * @brief Adds inventory item and associated sensor to specified vector.
1061*adc4f0dbSShawn McCarney  *
1062*adc4f0dbSShawn McCarney  * Adds a new InventoryItem to the vector if necessary.  Searches for an
1063*adc4f0dbSShawn McCarney  * existing InventoryItem with the specified object path.  If not found, one is
1064*adc4f0dbSShawn McCarney  * added to the vector.
1065*adc4f0dbSShawn McCarney  *
1066*adc4f0dbSShawn McCarney  * Next, the specified sensor is added to the set of sensors associated with the
1067*adc4f0dbSShawn McCarney  * InventoryItem.
1068*adc4f0dbSShawn McCarney  *
1069*adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
1070*adc4f0dbSShawn McCarney  * @param invItemObjPath D-Bus object path of inventory item.
1071*adc4f0dbSShawn McCarney  * @param sensorObjPath D-Bus object path of sensor
1072*adc4f0dbSShawn McCarney  */
1073*adc4f0dbSShawn McCarney static void
1074*adc4f0dbSShawn McCarney     addInventoryItem(std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1075*adc4f0dbSShawn McCarney                      const std::string& invItemObjPath,
1076*adc4f0dbSShawn McCarney                      const std::string& sensorObjPath)
1077*adc4f0dbSShawn McCarney {
1078*adc4f0dbSShawn McCarney     // Look for inventory item in vector
1079*adc4f0dbSShawn McCarney     InventoryItem* inventoryItem =
1080*adc4f0dbSShawn McCarney         findInventoryItem(inventoryItems, invItemObjPath);
1081*adc4f0dbSShawn McCarney 
1082*adc4f0dbSShawn McCarney     // If inventory item doesn't exist in vector, add it
1083*adc4f0dbSShawn McCarney     if (inventoryItem == nullptr)
1084*adc4f0dbSShawn McCarney     {
1085*adc4f0dbSShawn McCarney         inventoryItems->emplace_back(invItemObjPath);
1086*adc4f0dbSShawn McCarney         inventoryItem = &(inventoryItems->back());
1087*adc4f0dbSShawn McCarney     }
1088*adc4f0dbSShawn McCarney 
1089*adc4f0dbSShawn McCarney     // Add sensor to set of sensors associated with inventory item
1090*adc4f0dbSShawn McCarney     inventoryItem->sensors.emplace(sensorObjPath);
1091*adc4f0dbSShawn McCarney }
1092*adc4f0dbSShawn McCarney 
1093*adc4f0dbSShawn McCarney /**
1094*adc4f0dbSShawn McCarney  * @brief Stores D-Bus data in the specified inventory item.
1095*adc4f0dbSShawn McCarney  *
1096*adc4f0dbSShawn McCarney  * Finds D-Bus data in the specified map of interfaces.  Stores the data in the
1097*adc4f0dbSShawn McCarney  * specified InventoryItem.
1098*adc4f0dbSShawn McCarney  *
1099*adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
1100*adc4f0dbSShawn McCarney  * response.
1101*adc4f0dbSShawn McCarney  *
1102*adc4f0dbSShawn McCarney  * @param inventoryItem Inventory item where data will be stored.
1103*adc4f0dbSShawn McCarney  * @param interfacesDict Map containing D-Bus interfaces and their properties
1104*adc4f0dbSShawn McCarney  * for the specified inventory item.
1105*adc4f0dbSShawn McCarney  */
1106*adc4f0dbSShawn McCarney static void storeInventoryItemData(
1107*adc4f0dbSShawn McCarney     InventoryItem& inventoryItem,
11088fb49dd6SShawn McCarney     const boost::container::flat_map<
11098fb49dd6SShawn McCarney         std::string, boost::container::flat_map<std::string, SensorVariant>>&
11108fb49dd6SShawn McCarney         interfacesDict)
11118fb49dd6SShawn McCarney {
1112*adc4f0dbSShawn McCarney     // Get properties from Inventory.Item interface
1113*adc4f0dbSShawn McCarney     auto interfaceIt =
1114*adc4f0dbSShawn McCarney         interfacesDict.find("xyz.openbmc_project.Inventory.Item");
1115*adc4f0dbSShawn McCarney     if (interfaceIt != interfacesDict.end())
11168fb49dd6SShawn McCarney     {
1117*adc4f0dbSShawn McCarney         auto propertyIt = interfaceIt->second.find("Present");
1118*adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
11198fb49dd6SShawn McCarney         {
1120*adc4f0dbSShawn McCarney             const bool* value = std::get_if<bool>(&propertyIt->second);
1121*adc4f0dbSShawn McCarney             if (value != nullptr)
11228fb49dd6SShawn McCarney             {
1123*adc4f0dbSShawn McCarney                 inventoryItem.isPresent = *value;
11248fb49dd6SShawn McCarney             }
11258fb49dd6SShawn McCarney         }
11268fb49dd6SShawn McCarney     }
11278fb49dd6SShawn McCarney 
1128*adc4f0dbSShawn McCarney     // Check if Inventory.Item.PowerSupply interface is present
1129*adc4f0dbSShawn McCarney     interfaceIt =
1130*adc4f0dbSShawn McCarney         interfacesDict.find("xyz.openbmc_project.Inventory.Item.PowerSupply");
1131*adc4f0dbSShawn McCarney     if (interfaceIt != interfacesDict.end())
11328fb49dd6SShawn McCarney     {
1133*adc4f0dbSShawn McCarney         inventoryItem.isPowerSupply = true;
11348fb49dd6SShawn McCarney     }
1135*adc4f0dbSShawn McCarney 
1136*adc4f0dbSShawn McCarney     // Get properties from Inventory.Decorator.Asset interface
1137*adc4f0dbSShawn McCarney     interfaceIt =
1138*adc4f0dbSShawn McCarney         interfacesDict.find("xyz.openbmc_project.Inventory.Decorator.Asset");
1139*adc4f0dbSShawn McCarney     if (interfaceIt != interfacesDict.end())
1140*adc4f0dbSShawn McCarney     {
1141*adc4f0dbSShawn McCarney         auto propertyIt = interfaceIt->second.find("Manufacturer");
1142*adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1143*adc4f0dbSShawn McCarney         {
1144*adc4f0dbSShawn McCarney             const std::string* value =
1145*adc4f0dbSShawn McCarney                 std::get_if<std::string>(&propertyIt->second);
1146*adc4f0dbSShawn McCarney             if (value != nullptr)
1147*adc4f0dbSShawn McCarney             {
1148*adc4f0dbSShawn McCarney                 inventoryItem.manufacturer = *value;
1149*adc4f0dbSShawn McCarney             }
1150*adc4f0dbSShawn McCarney         }
1151*adc4f0dbSShawn McCarney 
1152*adc4f0dbSShawn McCarney         propertyIt = interfaceIt->second.find("Model");
1153*adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1154*adc4f0dbSShawn McCarney         {
1155*adc4f0dbSShawn McCarney             const std::string* value =
1156*adc4f0dbSShawn McCarney                 std::get_if<std::string>(&propertyIt->second);
1157*adc4f0dbSShawn McCarney             if (value != nullptr)
1158*adc4f0dbSShawn McCarney             {
1159*adc4f0dbSShawn McCarney                 inventoryItem.model = *value;
1160*adc4f0dbSShawn McCarney             }
1161*adc4f0dbSShawn McCarney         }
1162*adc4f0dbSShawn McCarney 
1163*adc4f0dbSShawn McCarney         propertyIt = interfaceIt->second.find("PartNumber");
1164*adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1165*adc4f0dbSShawn McCarney         {
1166*adc4f0dbSShawn McCarney             const std::string* value =
1167*adc4f0dbSShawn McCarney                 std::get_if<std::string>(&propertyIt->second);
1168*adc4f0dbSShawn McCarney             if (value != nullptr)
1169*adc4f0dbSShawn McCarney             {
1170*adc4f0dbSShawn McCarney                 inventoryItem.partNumber = *value;
1171*adc4f0dbSShawn McCarney             }
1172*adc4f0dbSShawn McCarney         }
1173*adc4f0dbSShawn McCarney 
1174*adc4f0dbSShawn McCarney         propertyIt = interfaceIt->second.find("SerialNumber");
1175*adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1176*adc4f0dbSShawn McCarney         {
1177*adc4f0dbSShawn McCarney             const std::string* value =
1178*adc4f0dbSShawn McCarney                 std::get_if<std::string>(&propertyIt->second);
1179*adc4f0dbSShawn McCarney             if (value != nullptr)
1180*adc4f0dbSShawn McCarney             {
1181*adc4f0dbSShawn McCarney                 inventoryItem.serialNumber = *value;
1182*adc4f0dbSShawn McCarney             }
1183*adc4f0dbSShawn McCarney         }
1184*adc4f0dbSShawn McCarney     }
1185*adc4f0dbSShawn McCarney 
1186*adc4f0dbSShawn McCarney     // Get properties from State.Decorator.OperationalStatus interface
1187*adc4f0dbSShawn McCarney     interfaceIt = interfacesDict.find(
1188*adc4f0dbSShawn McCarney         "xyz.openbmc_project.State.Decorator.OperationalStatus");
1189*adc4f0dbSShawn McCarney     if (interfaceIt != interfacesDict.end())
1190*adc4f0dbSShawn McCarney     {
1191*adc4f0dbSShawn McCarney         auto propertyIt = interfaceIt->second.find("Functional");
1192*adc4f0dbSShawn McCarney         if (propertyIt != interfaceIt->second.end())
1193*adc4f0dbSShawn McCarney         {
1194*adc4f0dbSShawn McCarney             const bool* value = std::get_if<bool>(&propertyIt->second);
1195*adc4f0dbSShawn McCarney             if (value != nullptr)
1196*adc4f0dbSShawn McCarney             {
1197*adc4f0dbSShawn McCarney                 inventoryItem.isFunctional = *value;
11988fb49dd6SShawn McCarney             }
11998fb49dd6SShawn McCarney         }
12008fb49dd6SShawn McCarney     }
12018fb49dd6SShawn McCarney }
12028fb49dd6SShawn McCarney 
12038fb49dd6SShawn McCarney /**
1204*adc4f0dbSShawn McCarney  * @brief Gets D-Bus data for inventory items associated with sensors.
12058fb49dd6SShawn McCarney  *
1206*adc4f0dbSShawn McCarney  * Uses the specified connections (services) to obtain D-Bus data for inventory
1207*adc4f0dbSShawn McCarney  * items associated with sensors.  Stores the resulting data in the
1208*adc4f0dbSShawn McCarney  * inventoryItems vector.
12098fb49dd6SShawn McCarney  *
1210*adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
1211*adc4f0dbSShawn McCarney  * response.
1212*adc4f0dbSShawn McCarney  *
1213*adc4f0dbSShawn McCarney  * Finds the inventory item data asynchronously.  Invokes callback when data has
1214*adc4f0dbSShawn McCarney  * been obtained.
1215*adc4f0dbSShawn McCarney  *
1216*adc4f0dbSShawn McCarney  * The callback must have the following signature:
1217*adc4f0dbSShawn McCarney  *   @code
1218*adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1219*adc4f0dbSShawn McCarney  *   @endcode
1220*adc4f0dbSShawn McCarney  *
1221*adc4f0dbSShawn McCarney  * This function is called recursively, obtaining data asynchronously from one
1222*adc4f0dbSShawn McCarney  * connection in each call.  This ensures the callback is not invoked until the
1223*adc4f0dbSShawn McCarney  * last asynchronous function has completed.
12248fb49dd6SShawn McCarney  *
12258fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
1226*adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
1227*adc4f0dbSShawn McCarney  * @param invConnections Connections that provide data for the inventory items.
12288fb49dd6SShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
12298fb49dd6SShawn McCarney  * implements ObjectManager.
1230*adc4f0dbSShawn McCarney  * @param callback Callback to invoke when inventory data has been obtained.
1231*adc4f0dbSShawn McCarney  * @param invConnectionsIndex Current index in invConnections.  Only specified
1232*adc4f0dbSShawn McCarney  * in recursive calls to this function.
12338fb49dd6SShawn McCarney  */
1234*adc4f0dbSShawn McCarney template <typename Callback>
1235*adc4f0dbSShawn McCarney static void getInventoryItemsData(
12368fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1237*adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
12388fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_set<std::string>> invConnections,
12398fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1240*adc4f0dbSShawn McCarney         objectMgrPaths,
1241*adc4f0dbSShawn McCarney     Callback&& callback, int invConnectionsIndex = 0)
12428fb49dd6SShawn McCarney {
1243*adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsData enter";
12448fb49dd6SShawn McCarney 
1245*adc4f0dbSShawn McCarney     // If no more connections left, call callback
1246*adc4f0dbSShawn McCarney     if (invConnectionsIndex >= invConnections->size())
12478fb49dd6SShawn McCarney     {
1248*adc4f0dbSShawn McCarney         callback(inventoryItems);
1249*adc4f0dbSShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemsData exit";
1250*adc4f0dbSShawn McCarney         return;
1251*adc4f0dbSShawn McCarney     }
1252*adc4f0dbSShawn McCarney 
1253*adc4f0dbSShawn McCarney     // Get inventory item data from current connection
1254*adc4f0dbSShawn McCarney     auto it = invConnections->nth(invConnectionsIndex);
1255*adc4f0dbSShawn McCarney     if (it != invConnections->end())
1256*adc4f0dbSShawn McCarney     {
1257*adc4f0dbSShawn McCarney         const std::string& invConnection = *it;
1258*adc4f0dbSShawn McCarney 
12598fb49dd6SShawn McCarney         // Response handler for GetManagedObjects
1260*adc4f0dbSShawn McCarney         auto respHandler = [sensorsAsyncResp, inventoryItems, invConnections,
1261*adc4f0dbSShawn McCarney                             objectMgrPaths, callback{std::move(callback)},
1262*adc4f0dbSShawn McCarney                             invConnectionsIndex](
1263*adc4f0dbSShawn McCarney                                const boost::system::error_code ec,
12648fb49dd6SShawn McCarney                                ManagedObjectsVectorType& resp) {
1265*adc4f0dbSShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemsData respHandler enter";
12668fb49dd6SShawn McCarney             if (ec)
12678fb49dd6SShawn McCarney             {
12688fb49dd6SShawn McCarney                 BMCWEB_LOG_ERROR
1269*adc4f0dbSShawn McCarney                     << "getInventoryItemsData respHandler DBus error " << ec;
12708fb49dd6SShawn McCarney                 messages::internalError(sensorsAsyncResp->res);
12718fb49dd6SShawn McCarney                 return;
12728fb49dd6SShawn McCarney             }
12738fb49dd6SShawn McCarney 
12748fb49dd6SShawn McCarney             // Loop through returned object paths
12758fb49dd6SShawn McCarney             for (const auto& objDictEntry : resp)
12768fb49dd6SShawn McCarney             {
12778fb49dd6SShawn McCarney                 const std::string& objPath =
12788fb49dd6SShawn McCarney                     static_cast<const std::string&>(objDictEntry.first);
12798fb49dd6SShawn McCarney 
1280*adc4f0dbSShawn McCarney                 // If this object path is one of the specified inventory items
1281*adc4f0dbSShawn McCarney                 InventoryItem* inventoryItem =
1282*adc4f0dbSShawn McCarney                     findInventoryItem(inventoryItems, objPath);
1283*adc4f0dbSShawn McCarney                 if (inventoryItem != nullptr)
12848fb49dd6SShawn McCarney                 {
1285*adc4f0dbSShawn McCarney                     // Store inventory data in InventoryItem
1286*adc4f0dbSShawn McCarney                     storeInventoryItemData(*inventoryItem, objDictEntry.second);
12878fb49dd6SShawn McCarney                 }
12888fb49dd6SShawn McCarney             }
12898fb49dd6SShawn McCarney 
1290*adc4f0dbSShawn McCarney             // Recurse to get inventory item data from next connection
1291*adc4f0dbSShawn McCarney             getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1292*adc4f0dbSShawn McCarney                                   invConnections, objectMgrPaths,
1293*adc4f0dbSShawn McCarney                                   std::move(callback), invConnectionsIndex + 1);
1294*adc4f0dbSShawn McCarney 
1295*adc4f0dbSShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemsData respHandler exit";
12968fb49dd6SShawn McCarney         };
12978fb49dd6SShawn McCarney 
12988fb49dd6SShawn McCarney         // Find DBus object path that implements ObjectManager for the current
12998fb49dd6SShawn McCarney         // connection.  If no mapping found, default to "/".
13008fb49dd6SShawn McCarney         auto iter = objectMgrPaths->find(invConnection);
13018fb49dd6SShawn McCarney         const std::string& objectMgrPath =
13028fb49dd6SShawn McCarney             (iter != objectMgrPaths->end()) ? iter->second : "/";
13038fb49dd6SShawn McCarney         BMCWEB_LOG_DEBUG << "ObjectManager path for " << invConnection << " is "
13048fb49dd6SShawn McCarney                          << objectMgrPath;
13058fb49dd6SShawn McCarney 
13068fb49dd6SShawn McCarney         // Get all object paths and their interfaces for current connection
13078fb49dd6SShawn McCarney         crow::connections::systemBus->async_method_call(
13088fb49dd6SShawn McCarney             std::move(respHandler), invConnection, objectMgrPath,
13098fb49dd6SShawn McCarney             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
13108fb49dd6SShawn McCarney     }
13118fb49dd6SShawn McCarney 
1312*adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsData exit";
13138fb49dd6SShawn McCarney }
13148fb49dd6SShawn McCarney 
13158fb49dd6SShawn McCarney /**
1316*adc4f0dbSShawn McCarney  * @brief Gets connections that provide D-Bus data for inventory items.
13178fb49dd6SShawn McCarney  *
1318*adc4f0dbSShawn McCarney  * Gets the D-Bus connections (services) that provide data for the inventory
1319*adc4f0dbSShawn McCarney  * items that are associated with sensors.
13208fb49dd6SShawn McCarney  *
13218fb49dd6SShawn McCarney  * Finds the connections asynchronously.  Invokes callback when information has
13228fb49dd6SShawn McCarney  * been obtained.
13238fb49dd6SShawn McCarney  *
13248fb49dd6SShawn McCarney  * The callback must have the following signature:
13258fb49dd6SShawn McCarney  *   @code
13268fb49dd6SShawn McCarney  *   callback(std::shared_ptr<boost::container::flat_set<std::string>>
13278fb49dd6SShawn McCarney  *            invConnections)
13288fb49dd6SShawn McCarney  *   @endcode
13298fb49dd6SShawn McCarney  *
13308fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
1331*adc4f0dbSShawn McCarney  * @param inventoryItems D-Bus inventory items associated with sensors.
13328fb49dd6SShawn McCarney  * @param callback Callback to invoke when connections have been obtained.
13338fb49dd6SShawn McCarney  */
13348fb49dd6SShawn McCarney template <typename Callback>
13358fb49dd6SShawn McCarney static void getInventoryItemsConnections(
13368fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1337*adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
13388fb49dd6SShawn McCarney     Callback&& callback)
13398fb49dd6SShawn McCarney {
13408fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsConnections enter";
13418fb49dd6SShawn McCarney 
13428fb49dd6SShawn McCarney     const std::string path = "/xyz/openbmc_project/inventory";
1343*adc4f0dbSShawn McCarney     const std::array<std::string, 4> interfaces = {
13448fb49dd6SShawn McCarney         "xyz.openbmc_project.Inventory.Item",
1345*adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Item.PowerSupply",
1346*adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Decorator.Asset",
13478fb49dd6SShawn McCarney         "xyz.openbmc_project.State.Decorator.OperationalStatus"};
13488fb49dd6SShawn McCarney 
13498fb49dd6SShawn McCarney     // Response handler for parsing output from GetSubTree
13508fb49dd6SShawn McCarney     auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
1351*adc4f0dbSShawn McCarney                         inventoryItems](const boost::system::error_code ec,
13528fb49dd6SShawn McCarney                                         const GetSubTreeType& subtree) {
13538fb49dd6SShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler enter";
13548fb49dd6SShawn McCarney         if (ec)
13558fb49dd6SShawn McCarney         {
13568fb49dd6SShawn McCarney             messages::internalError(sensorsAsyncResp->res);
13578fb49dd6SShawn McCarney             BMCWEB_LOG_ERROR
13588fb49dd6SShawn McCarney                 << "getInventoryItemsConnections respHandler DBus error " << ec;
13598fb49dd6SShawn McCarney             return;
13608fb49dd6SShawn McCarney         }
13618fb49dd6SShawn McCarney 
13628fb49dd6SShawn McCarney         // Make unique list of connections for desired inventory items
13638fb49dd6SShawn McCarney         std::shared_ptr<boost::container::flat_set<std::string>>
13648fb49dd6SShawn McCarney             invConnections =
13658fb49dd6SShawn McCarney                 std::make_shared<boost::container::flat_set<std::string>>();
13668fb49dd6SShawn McCarney         invConnections->reserve(8);
13678fb49dd6SShawn McCarney 
13688fb49dd6SShawn McCarney         // Loop through objects from GetSubTree
13698fb49dd6SShawn McCarney         for (const std::pair<
13708fb49dd6SShawn McCarney                  std::string,
13718fb49dd6SShawn McCarney                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
13728fb49dd6SShawn McCarney                  object : subtree)
13738fb49dd6SShawn McCarney         {
1374*adc4f0dbSShawn McCarney             // Check if object path is one of the specified inventory items
13758fb49dd6SShawn McCarney             const std::string& objPath = object.first;
1376*adc4f0dbSShawn McCarney             if (findInventoryItem(inventoryItems, objPath) != nullptr)
13778fb49dd6SShawn McCarney             {
13788fb49dd6SShawn McCarney                 // Store all connections to inventory item
13798fb49dd6SShawn McCarney                 for (const std::pair<std::string, std::vector<std::string>>&
13808fb49dd6SShawn McCarney                          objData : object.second)
13818fb49dd6SShawn McCarney                 {
13828fb49dd6SShawn McCarney                     const std::string& invConnection = objData.first;
13838fb49dd6SShawn McCarney                     invConnections->insert(invConnection);
13848fb49dd6SShawn McCarney                 }
13858fb49dd6SShawn McCarney             }
13868fb49dd6SShawn McCarney         }
13878fb49dd6SShawn McCarney         callback(invConnections);
13888fb49dd6SShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler exit";
13898fb49dd6SShawn McCarney     };
13908fb49dd6SShawn McCarney 
13918fb49dd6SShawn McCarney     // Make call to ObjectMapper to find all inventory items
13928fb49dd6SShawn McCarney     crow::connections::systemBus->async_method_call(
13938fb49dd6SShawn McCarney         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
13948fb49dd6SShawn McCarney         "/xyz/openbmc_project/object_mapper",
13958fb49dd6SShawn McCarney         "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 0, interfaces);
13968fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemsConnections exit";
13978fb49dd6SShawn McCarney }
13988fb49dd6SShawn McCarney 
13998fb49dd6SShawn McCarney /**
1400*adc4f0dbSShawn McCarney  * @brief Gets associations from sensors to inventory items.
14018fb49dd6SShawn McCarney  *
14028fb49dd6SShawn McCarney  * Looks for ObjectMapper associations from the specified sensors to related
1403*adc4f0dbSShawn McCarney  * inventory items.
14048fb49dd6SShawn McCarney  *
14058fb49dd6SShawn McCarney  * Finds the inventory items asynchronously.  Invokes callback when information
14068fb49dd6SShawn McCarney  * has been obtained.
14078fb49dd6SShawn McCarney  *
14088fb49dd6SShawn McCarney  * The callback must have the following signature:
14098fb49dd6SShawn McCarney  *   @code
1410*adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
14118fb49dd6SShawn McCarney  *   @endcode
14128fb49dd6SShawn McCarney  *
14138fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
14148fb49dd6SShawn McCarney  * @param sensorNames All sensors within the current chassis.
14158fb49dd6SShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
14168fb49dd6SShawn McCarney  * implements ObjectManager.
14178fb49dd6SShawn McCarney  * @param callback Callback to invoke when inventory items have been obtained.
14188fb49dd6SShawn McCarney  */
14198fb49dd6SShawn McCarney template <typename Callback>
1420*adc4f0dbSShawn McCarney static void getInventoryItemAssociations(
14218fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
14228fb49dd6SShawn McCarney     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
14238fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
14248fb49dd6SShawn McCarney         objectMgrPaths,
14258fb49dd6SShawn McCarney     Callback&& callback)
14268fb49dd6SShawn McCarney {
1427*adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemAssociations enter";
14288fb49dd6SShawn McCarney 
14298fb49dd6SShawn McCarney     // Response handler for GetManagedObjects
14308fb49dd6SShawn McCarney     auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
14318fb49dd6SShawn McCarney                         sensorNames](const boost::system::error_code ec,
14328fb49dd6SShawn McCarney                                      dbus::utility::ManagedObjectType& resp) {
1433*adc4f0dbSShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemAssociations respHandler enter";
14348fb49dd6SShawn McCarney         if (ec)
14358fb49dd6SShawn McCarney         {
1436*adc4f0dbSShawn McCarney             BMCWEB_LOG_ERROR
1437*adc4f0dbSShawn McCarney                 << "getInventoryItemAssociations respHandler DBus error " << ec;
14388fb49dd6SShawn McCarney             messages::internalError(sensorsAsyncResp->res);
14398fb49dd6SShawn McCarney             return;
14408fb49dd6SShawn McCarney         }
14418fb49dd6SShawn McCarney 
1442*adc4f0dbSShawn McCarney         // Create vector to hold list of inventory items
1443*adc4f0dbSShawn McCarney         std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1444*adc4f0dbSShawn McCarney             std::make_shared<std::vector<InventoryItem>>();
1445*adc4f0dbSShawn McCarney 
14468fb49dd6SShawn McCarney         // Loop through returned object paths
14478fb49dd6SShawn McCarney         std::string sensorAssocPath;
14488fb49dd6SShawn McCarney         sensorAssocPath.reserve(128); // avoid memory allocations
14498fb49dd6SShawn McCarney         for (const auto& objDictEntry : resp)
14508fb49dd6SShawn McCarney         {
14518fb49dd6SShawn McCarney             const std::string& objPath =
14528fb49dd6SShawn McCarney                 static_cast<const std::string&>(objDictEntry.first);
14538fb49dd6SShawn McCarney             const boost::container::flat_map<
14548fb49dd6SShawn McCarney                 std::string, boost::container::flat_map<
14558fb49dd6SShawn McCarney                                  std::string, dbus::utility::DbusVariantType>>&
14568fb49dd6SShawn McCarney                 interfacesDict = objDictEntry.second;
14578fb49dd6SShawn McCarney 
14588fb49dd6SShawn McCarney             // If path is inventory association for one of the specified sensors
14598fb49dd6SShawn McCarney             for (const std::string& sensorName : *sensorNames)
14608fb49dd6SShawn McCarney             {
14618fb49dd6SShawn McCarney                 sensorAssocPath = sensorName;
14628fb49dd6SShawn McCarney                 sensorAssocPath += "/inventory";
14638fb49dd6SShawn McCarney                 if (objPath == sensorAssocPath)
14648fb49dd6SShawn McCarney                 {
14658fb49dd6SShawn McCarney                     // Get Association interface for object path
14668fb49dd6SShawn McCarney                     auto assocIt =
14678fb49dd6SShawn McCarney                         interfacesDict.find("xyz.openbmc_project.Association");
14688fb49dd6SShawn McCarney                     if (assocIt != interfacesDict.end())
14698fb49dd6SShawn McCarney                     {
14708fb49dd6SShawn McCarney                         // Get inventory item from end point
14718fb49dd6SShawn McCarney                         auto endpointsIt = assocIt->second.find("endpoints");
14728fb49dd6SShawn McCarney                         if (endpointsIt != assocIt->second.end())
14738fb49dd6SShawn McCarney                         {
14748fb49dd6SShawn McCarney                             const std::vector<std::string>* endpoints =
14758fb49dd6SShawn McCarney                                 std::get_if<std::vector<std::string>>(
14768fb49dd6SShawn McCarney                                     &endpointsIt->second);
14778fb49dd6SShawn McCarney                             if ((endpoints != nullptr) && !endpoints->empty())
14788fb49dd6SShawn McCarney                             {
1479*adc4f0dbSShawn McCarney                                 // Add inventory item to vector
1480*adc4f0dbSShawn McCarney                                 const std::string& invItemPath =
1481*adc4f0dbSShawn McCarney                                     endpoints->front();
1482*adc4f0dbSShawn McCarney                                 addInventoryItem(inventoryItems, invItemPath,
1483*adc4f0dbSShawn McCarney                                                  sensorName);
14848fb49dd6SShawn McCarney                             }
14858fb49dd6SShawn McCarney                         }
14868fb49dd6SShawn McCarney                     }
14878fb49dd6SShawn McCarney                     break;
14888fb49dd6SShawn McCarney                 }
14898fb49dd6SShawn McCarney             }
14908fb49dd6SShawn McCarney         }
14918fb49dd6SShawn McCarney 
1492*adc4f0dbSShawn McCarney         callback(inventoryItems);
1493*adc4f0dbSShawn McCarney         BMCWEB_LOG_DEBUG << "getInventoryItemAssociations respHandler exit";
14948fb49dd6SShawn McCarney     };
14958fb49dd6SShawn McCarney 
14968fb49dd6SShawn McCarney     // Find DBus object path that implements ObjectManager for ObjectMapper
14978fb49dd6SShawn McCarney     std::string connection = "xyz.openbmc_project.ObjectMapper";
14988fb49dd6SShawn McCarney     auto iter = objectMgrPaths->find(connection);
14998fb49dd6SShawn McCarney     const std::string& objectMgrPath =
15008fb49dd6SShawn McCarney         (iter != objectMgrPaths->end()) ? iter->second : "/";
15018fb49dd6SShawn McCarney     BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
15028fb49dd6SShawn McCarney                      << objectMgrPath;
15038fb49dd6SShawn McCarney 
15048fb49dd6SShawn McCarney     // Call GetManagedObjects on the ObjectMapper to get all associations
15058fb49dd6SShawn McCarney     crow::connections::systemBus->async_method_call(
15068fb49dd6SShawn McCarney         std::move(respHandler), connection, objectMgrPath,
15078fb49dd6SShawn McCarney         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
15088fb49dd6SShawn McCarney 
1509*adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItemAssociations exit";
15108fb49dd6SShawn McCarney }
15118fb49dd6SShawn McCarney 
15128fb49dd6SShawn McCarney /**
1513*adc4f0dbSShawn McCarney  * @brief Gets inventory items associated with sensors.
15148fb49dd6SShawn McCarney  *
15158fb49dd6SShawn McCarney  * Finds the inventory items that are associated with the specified sensors.
1516*adc4f0dbSShawn McCarney  * Then gets D-Bus data for the inventory items, such as presence and VPD.
15178fb49dd6SShawn McCarney  *
1518*adc4f0dbSShawn McCarney  * This data is later used to provide sensor property values in the JSON
1519*adc4f0dbSShawn McCarney  * response.
15208fb49dd6SShawn McCarney  *
1521*adc4f0dbSShawn McCarney  * Finds the inventory items asynchronously.  Invokes callback when the
1522*adc4f0dbSShawn McCarney  * inventory items have been obtained.
1523*adc4f0dbSShawn McCarney  *
1524*adc4f0dbSShawn McCarney  * The callback must have the following signature:
1525*adc4f0dbSShawn McCarney  *   @code
1526*adc4f0dbSShawn McCarney  *   callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1527*adc4f0dbSShawn McCarney  *   @endcode
15288fb49dd6SShawn McCarney  *
15298fb49dd6SShawn McCarney  * @param sensorsAsyncResp Pointer to object holding response data.
15308fb49dd6SShawn McCarney  * @param sensorNames All sensors within the current chassis.
15318fb49dd6SShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
15328fb49dd6SShawn McCarney  * implements ObjectManager.
1533*adc4f0dbSShawn McCarney  * @param callback Callback to invoke when inventory items have been obtained.
15348fb49dd6SShawn McCarney  */
1535*adc4f0dbSShawn McCarney template <typename Callback>
1536*adc4f0dbSShawn McCarney static void getInventoryItems(
15378fb49dd6SShawn McCarney     std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
15388fb49dd6SShawn McCarney     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
15398fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1540*adc4f0dbSShawn McCarney         objectMgrPaths,
1541*adc4f0dbSShawn McCarney     Callback&& callback)
15428fb49dd6SShawn McCarney {
1543*adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItems enter";
1544*adc4f0dbSShawn McCarney     auto getInventoryItemAssociationsCb =
1545*adc4f0dbSShawn McCarney         [sensorsAsyncResp, objectMgrPaths, callback{std::move(callback)}](
1546*adc4f0dbSShawn McCarney             std::shared_ptr<std::vector<InventoryItem>> inventoryItems) {
1547*adc4f0dbSShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemAssociationsCb enter";
15488fb49dd6SShawn McCarney             auto getInventoryItemsConnectionsCb =
1549*adc4f0dbSShawn McCarney                 [sensorsAsyncResp, inventoryItems, objectMgrPaths,
1550*adc4f0dbSShawn McCarney                  callback{std::move(callback)}](
15518fb49dd6SShawn McCarney                     std::shared_ptr<boost::container::flat_set<std::string>>
15528fb49dd6SShawn McCarney                         invConnections) {
15538fb49dd6SShawn McCarney                     BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb enter";
15548fb49dd6SShawn McCarney 
1555*adc4f0dbSShawn McCarney                     // Get inventory item data from connections
1556*adc4f0dbSShawn McCarney                     getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1557*adc4f0dbSShawn McCarney                                           invConnections, objectMgrPaths,
1558*adc4f0dbSShawn McCarney                                           std::move(callback));
15598fb49dd6SShawn McCarney 
15608fb49dd6SShawn McCarney                     BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb exit";
15618fb49dd6SShawn McCarney                 };
15628fb49dd6SShawn McCarney 
1563*adc4f0dbSShawn McCarney             // Get connections that provide inventory item data
15648fb49dd6SShawn McCarney             getInventoryItemsConnections(
1565*adc4f0dbSShawn McCarney                 sensorsAsyncResp, inventoryItems,
15668fb49dd6SShawn McCarney                 std::move(getInventoryItemsConnectionsCb));
1567*adc4f0dbSShawn McCarney             BMCWEB_LOG_DEBUG << "getInventoryItemAssociationsCb exit";
15688fb49dd6SShawn McCarney         };
15698fb49dd6SShawn McCarney 
1570*adc4f0dbSShawn McCarney     // Get associations from sensors to inventory items
1571*adc4f0dbSShawn McCarney     getInventoryItemAssociations(sensorsAsyncResp, sensorNames, objectMgrPaths,
1572*adc4f0dbSShawn McCarney                                  std::move(getInventoryItemAssociationsCb));
1573*adc4f0dbSShawn McCarney     BMCWEB_LOG_DEBUG << "getInventoryItems exit";
1574*adc4f0dbSShawn McCarney }
1575*adc4f0dbSShawn McCarney 
1576*adc4f0dbSShawn McCarney /**
1577*adc4f0dbSShawn McCarney  * @brief Returns JSON PowerSupply object for the specified inventory item.
1578*adc4f0dbSShawn McCarney  *
1579*adc4f0dbSShawn McCarney  * Searches for a JSON PowerSupply object that matches the specified inventory
1580*adc4f0dbSShawn McCarney  * item.  If one is not found, a new PowerSupply object is added to the JSON
1581*adc4f0dbSShawn McCarney  * array.
1582*adc4f0dbSShawn McCarney  *
1583*adc4f0dbSShawn McCarney  * Multiple sensors are often associated with one power supply inventory item.
1584*adc4f0dbSShawn McCarney  * As a result, multiple sensor values are stored in one JSON PowerSupply
1585*adc4f0dbSShawn McCarney  * object.
1586*adc4f0dbSShawn McCarney  *
1587*adc4f0dbSShawn McCarney  * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1588*adc4f0dbSShawn McCarney  * @param inventoryItem Inventory item for the power supply.
1589*adc4f0dbSShawn McCarney  * @param chassisId Chassis that contains the power supply.
1590*adc4f0dbSShawn McCarney  * @return JSON PowerSupply object for the specified inventory item.
1591*adc4f0dbSShawn McCarney  */
1592*adc4f0dbSShawn McCarney static nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
1593*adc4f0dbSShawn McCarney                                       const InventoryItem& inventoryItem,
1594*adc4f0dbSShawn McCarney                                       const std::string& chassisId)
1595*adc4f0dbSShawn McCarney {
1596*adc4f0dbSShawn McCarney     // Check if matching PowerSupply object already exists in JSON array
1597*adc4f0dbSShawn McCarney     for (nlohmann::json& powerSupply : powerSupplyArray)
1598*adc4f0dbSShawn McCarney     {
1599*adc4f0dbSShawn McCarney         if (powerSupply["MemberId"] == inventoryItem.name)
1600*adc4f0dbSShawn McCarney         {
1601*adc4f0dbSShawn McCarney             return powerSupply;
1602*adc4f0dbSShawn McCarney         }
1603*adc4f0dbSShawn McCarney     }
1604*adc4f0dbSShawn McCarney 
1605*adc4f0dbSShawn McCarney     // Add new PowerSupply object to JSON array
1606*adc4f0dbSShawn McCarney     powerSupplyArray.push_back({});
1607*adc4f0dbSShawn McCarney     nlohmann::json& powerSupply = powerSupplyArray.back();
1608*adc4f0dbSShawn McCarney     powerSupply["@odata.id"] =
1609*adc4f0dbSShawn McCarney         "/redfish/v1/Chassis/" + chassisId + "/Power#/PowerSupplies/";
1610*adc4f0dbSShawn McCarney     powerSupply["MemberId"] = inventoryItem.name;
1611*adc4f0dbSShawn McCarney     powerSupply["Name"] = boost::replace_all_copy(inventoryItem.name, "_", " ");
1612*adc4f0dbSShawn McCarney     powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1613*adc4f0dbSShawn McCarney     powerSupply["Model"] = inventoryItem.model;
1614*adc4f0dbSShawn McCarney     powerSupply["PartNumber"] = inventoryItem.partNumber;
1615*adc4f0dbSShawn McCarney     powerSupply["SerialNumber"] = inventoryItem.serialNumber;
1616*adc4f0dbSShawn McCarney     powerSupply["Status"]["State"] = getState(&inventoryItem);
1617*adc4f0dbSShawn McCarney 
1618*adc4f0dbSShawn McCarney     const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1619*adc4f0dbSShawn McCarney     powerSupply["Status"]["Health"] = health;
1620*adc4f0dbSShawn McCarney 
1621*adc4f0dbSShawn McCarney     return powerSupply;
16228fb49dd6SShawn McCarney }
16238fb49dd6SShawn McCarney 
16248fb49dd6SShawn McCarney /**
1625de629b6eSShawn McCarney  * @brief Gets the values of the specified sensors.
1626de629b6eSShawn McCarney  *
1627de629b6eSShawn McCarney  * Stores the results as JSON in the SensorsAsyncResp.
1628de629b6eSShawn McCarney  *
1629de629b6eSShawn McCarney  * Gets the sensor values asynchronously.  Stores the results later when the
1630de629b6eSShawn McCarney  * information has been obtained.
1631de629b6eSShawn McCarney  *
1632*adc4f0dbSShawn McCarney  * The sensorNames set contains all requested sensors for the current chassis.
1633de629b6eSShawn McCarney  *
1634de629b6eSShawn McCarney  * To minimize the number of DBus calls, the DBus method
1635de629b6eSShawn McCarney  * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1636de629b6eSShawn McCarney  * values of all sensors provided by a connection (service).
1637de629b6eSShawn McCarney  *
1638de629b6eSShawn McCarney  * The connections set contains all the connections that provide sensor values.
1639de629b6eSShawn McCarney  *
1640de629b6eSShawn McCarney  * The objectMgrPaths map contains mappings from a connection name to the
1641de629b6eSShawn McCarney  * corresponding DBus object path that implements ObjectManager.
1642de629b6eSShawn McCarney  *
1643*adc4f0dbSShawn McCarney  * The InventoryItem vector contains D-Bus inventory items associated with the
1644*adc4f0dbSShawn McCarney  * sensors.  Inventory item data is needed for some Redfish sensor properties.
1645*adc4f0dbSShawn McCarney  *
1646de629b6eSShawn McCarney  * @param SensorsAsyncResp Pointer to object holding response data.
1647*adc4f0dbSShawn McCarney  * @param sensorNames All requested sensors within the current chassis.
1648de629b6eSShawn McCarney  * @param connections Connections that provide sensor values.
1649de629b6eSShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
1650de629b6eSShawn McCarney  * implements ObjectManager.
1651*adc4f0dbSShawn McCarney  * @param inventoryItems Inventory items associated with the sensors.
1652de629b6eSShawn McCarney  */
1653de629b6eSShawn McCarney void getSensorData(
1654de629b6eSShawn McCarney     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
165549c53ac9SJohnathan Mantey     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
1656de629b6eSShawn McCarney     const boost::container::flat_set<std::string>& connections,
16578fb49dd6SShawn McCarney     std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1658*adc4f0dbSShawn McCarney         objectMgrPaths,
1659*adc4f0dbSShawn McCarney     std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1660de629b6eSShawn McCarney {
1661de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getSensorData enter";
1662de629b6eSShawn McCarney     // Get managed objects from all services exposing sensors
1663de629b6eSShawn McCarney     for (const std::string& connection : connections)
1664de629b6eSShawn McCarney     {
1665de629b6eSShawn McCarney         // Response handler to process managed objects
16668fb49dd6SShawn McCarney         auto getManagedObjectsCb = [SensorsAsyncResp, sensorNames,
1667*adc4f0dbSShawn McCarney                                     inventoryItems](
1668de629b6eSShawn McCarney                                        const boost::system::error_code ec,
1669de629b6eSShawn McCarney                                        ManagedObjectsVectorType& resp) {
1670de629b6eSShawn McCarney             BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
1671de629b6eSShawn McCarney             if (ec)
1672de629b6eSShawn McCarney             {
1673de629b6eSShawn McCarney                 BMCWEB_LOG_ERROR << "getManagedObjectsCb DBUS error: " << ec;
1674de629b6eSShawn McCarney                 messages::internalError(SensorsAsyncResp->res);
1675de629b6eSShawn McCarney                 return;
1676de629b6eSShawn McCarney             }
1677de629b6eSShawn McCarney             // Go through all objects and update response with sensor data
1678de629b6eSShawn McCarney             for (const auto& objDictEntry : resp)
1679de629b6eSShawn McCarney             {
1680de629b6eSShawn McCarney                 const std::string& objPath =
1681de629b6eSShawn McCarney                     static_cast<const std::string&>(objDictEntry.first);
1682de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "getManagedObjectsCb parsing object "
1683de629b6eSShawn McCarney                                  << objPath;
1684de629b6eSShawn McCarney 
1685de629b6eSShawn McCarney                 std::vector<std::string> split;
1686de629b6eSShawn McCarney                 // Reserve space for
1687de629b6eSShawn McCarney                 // /xyz/openbmc_project/sensors/<name>/<subname>
1688de629b6eSShawn McCarney                 split.reserve(6);
1689de629b6eSShawn McCarney                 boost::algorithm::split(split, objPath, boost::is_any_of("/"));
1690de629b6eSShawn McCarney                 if (split.size() < 6)
1691de629b6eSShawn McCarney                 {
1692de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << "Got path that isn't long enough "
1693de629b6eSShawn McCarney                                      << objPath;
1694de629b6eSShawn McCarney                     continue;
1695de629b6eSShawn McCarney                 }
1696de629b6eSShawn McCarney                 // These indexes aren't intuitive, as boost::split puts an empty
1697de629b6eSShawn McCarney                 // string at the beginning
1698de629b6eSShawn McCarney                 const std::string& sensorType = split[4];
1699de629b6eSShawn McCarney                 const std::string& sensorName = split[5];
1700de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "sensorName " << sensorName
1701de629b6eSShawn McCarney                                  << " sensorType " << sensorType;
170249c53ac9SJohnathan Mantey                 if (sensorNames->find(objPath) == sensorNames->end())
1703de629b6eSShawn McCarney                 {
1704de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << sensorName << " not in sensor list ";
1705de629b6eSShawn McCarney                     continue;
1706de629b6eSShawn McCarney                 }
1707de629b6eSShawn McCarney 
1708*adc4f0dbSShawn McCarney                 // Find inventory item (if any) associated with sensor
1709*adc4f0dbSShawn McCarney                 InventoryItem* inventoryItem =
1710*adc4f0dbSShawn McCarney                     findInventoryItemForSensor(inventoryItems, objPath);
1711*adc4f0dbSShawn McCarney 
1712de629b6eSShawn McCarney                 const char* fieldName = nullptr;
1713de629b6eSShawn McCarney                 if (sensorType == "temperature")
1714de629b6eSShawn McCarney                 {
1715de629b6eSShawn McCarney                     fieldName = "Temperatures";
1716de629b6eSShawn McCarney                 }
1717de629b6eSShawn McCarney                 else if (sensorType == "fan" || sensorType == "fan_tach" ||
1718de629b6eSShawn McCarney                          sensorType == "fan_pwm")
1719de629b6eSShawn McCarney                 {
1720de629b6eSShawn McCarney                     fieldName = "Fans";
1721de629b6eSShawn McCarney                 }
1722de629b6eSShawn McCarney                 else if (sensorType == "voltage")
1723de629b6eSShawn McCarney                 {
1724de629b6eSShawn McCarney                     fieldName = "Voltages";
1725de629b6eSShawn McCarney                 }
1726de629b6eSShawn McCarney                 else if (sensorType == "power")
1727de629b6eSShawn McCarney                 {
1728028f7ebcSEddie James                     if (!sensorName.compare("total_power"))
1729028f7ebcSEddie James                     {
1730028f7ebcSEddie James                         fieldName = "PowerControl";
1731028f7ebcSEddie James                     }
1732*adc4f0dbSShawn McCarney                     else if ((inventoryItem != nullptr) &&
1733*adc4f0dbSShawn McCarney                              (inventoryItem->isPowerSupply))
1734028f7ebcSEddie James                     {
1735de629b6eSShawn McCarney                         fieldName = "PowerSupplies";
1736de629b6eSShawn McCarney                     }
1737*adc4f0dbSShawn McCarney                     else
1738*adc4f0dbSShawn McCarney                     {
1739*adc4f0dbSShawn McCarney                         // Other power sensors are in SensorCollection
1740*adc4f0dbSShawn McCarney                         continue;
1741*adc4f0dbSShawn McCarney                     }
1742028f7ebcSEddie James                 }
1743de629b6eSShawn McCarney                 else
1744de629b6eSShawn McCarney                 {
1745de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << "Unsure how to handle sensorType "
1746de629b6eSShawn McCarney                                      << sensorType;
1747de629b6eSShawn McCarney                     continue;
1748de629b6eSShawn McCarney                 }
1749de629b6eSShawn McCarney 
1750de629b6eSShawn McCarney                 nlohmann::json& tempArray =
1751de629b6eSShawn McCarney                     SensorsAsyncResp->res.jsonValue[fieldName];
1752*adc4f0dbSShawn McCarney                 nlohmann::json* sensorJson = nullptr;
1753de629b6eSShawn McCarney 
1754*adc4f0dbSShawn McCarney                 if (fieldName == "PowerControl")
175549c53ac9SJohnathan Mantey                 {
1756*adc4f0dbSShawn McCarney                     if (tempArray.empty())
17577ab06f49SGunnar Mills                     {
17587ab06f49SGunnar Mills                         // Put multiple "sensors" into a single PowerControl.
17597ab06f49SGunnar Mills                         // Follows MemberId naming and naming in power.hpp.
17607ab06f49SGunnar Mills                         tempArray.push_back(
1761*adc4f0dbSShawn McCarney                             {{"@odata.id",
1762*adc4f0dbSShawn McCarney                               "/redfish/v1/Chassis/" +
17637ab06f49SGunnar Mills                                   SensorsAsyncResp->chassisId + "/" +
1764*adc4f0dbSShawn McCarney                                   SensorsAsyncResp->chassisSubNode + "#/" +
1765*adc4f0dbSShawn McCarney                                   fieldName + "/0"}});
1766*adc4f0dbSShawn McCarney                     }
1767*adc4f0dbSShawn McCarney                     sensorJson = &(tempArray.back());
1768*adc4f0dbSShawn McCarney                 }
1769*adc4f0dbSShawn McCarney                 else if (fieldName == "PowerSupplies")
1770*adc4f0dbSShawn McCarney                 {
1771*adc4f0dbSShawn McCarney                     if (inventoryItem != nullptr)
1772*adc4f0dbSShawn McCarney                     {
1773*adc4f0dbSShawn McCarney                         sensorJson =
1774*adc4f0dbSShawn McCarney                             &(getPowerSupply(tempArray, *inventoryItem,
1775*adc4f0dbSShawn McCarney                                              SensorsAsyncResp->chassisId));
1776*adc4f0dbSShawn McCarney                     }
177749c53ac9SJohnathan Mantey                 }
177849c53ac9SJohnathan Mantey                 else
177949c53ac9SJohnathan Mantey                 {
1780de629b6eSShawn McCarney                     tempArray.push_back(
178149c53ac9SJohnathan Mantey                         {{"@odata.id", "/redfish/v1/Chassis/" +
178249c53ac9SJohnathan Mantey                                            SensorsAsyncResp->chassisId + "/" +
178349c53ac9SJohnathan Mantey                                            SensorsAsyncResp->chassisSubNode +
178449c53ac9SJohnathan Mantey                                            "#/" + fieldName + "/"}});
1785*adc4f0dbSShawn McCarney                     sensorJson = &(tempArray.back());
178649c53ac9SJohnathan Mantey                 }
1787de629b6eSShawn McCarney 
1788*adc4f0dbSShawn McCarney                 if (sensorJson != nullptr)
1789*adc4f0dbSShawn McCarney                 {
1790de629b6eSShawn McCarney                     objectInterfacesToJson(sensorName, sensorType,
1791*adc4f0dbSShawn McCarney                                            objDictEntry.second, *sensorJson,
1792*adc4f0dbSShawn McCarney                                            inventoryItem);
1793*adc4f0dbSShawn McCarney                 }
1794de629b6eSShawn McCarney             }
179549c53ac9SJohnathan Mantey             if (SensorsAsyncResp.use_count() == 1)
179649c53ac9SJohnathan Mantey             {
179749c53ac9SJohnathan Mantey                 sortJSONResponse(SensorsAsyncResp);
179849c53ac9SJohnathan Mantey                 if (SensorsAsyncResp->chassisSubNode == "Thermal")
17998bd25ccdSJames Feist                 {
18008bd25ccdSJames Feist                     populateFanRedundancy(SensorsAsyncResp);
18018bd25ccdSJames Feist                 }
180249c53ac9SJohnathan Mantey             }
1803de629b6eSShawn McCarney             BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
1804de629b6eSShawn McCarney         };
1805de629b6eSShawn McCarney 
1806de629b6eSShawn McCarney         // Find DBus object path that implements ObjectManager for the current
1807de629b6eSShawn McCarney         // connection.  If no mapping found, default to "/".
18088fb49dd6SShawn McCarney         auto iter = objectMgrPaths->find(connection);
1809de629b6eSShawn McCarney         const std::string& objectMgrPath =
18108fb49dd6SShawn McCarney             (iter != objectMgrPaths->end()) ? iter->second : "/";
1811de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
1812de629b6eSShawn McCarney                          << objectMgrPath;
1813de629b6eSShawn McCarney 
1814de629b6eSShawn McCarney         crow::connections::systemBus->async_method_call(
1815de629b6eSShawn McCarney             getManagedObjectsCb, connection, objectMgrPath,
1816de629b6eSShawn McCarney             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1817de629b6eSShawn McCarney     };
1818de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getSensorData exit";
1819de629b6eSShawn McCarney }
1820de629b6eSShawn McCarney 
1821de629b6eSShawn McCarney /**
182208777fb0SLewanczyk, Dawid  * @brief Entry point for retrieving sensors data related to requested
182308777fb0SLewanczyk, Dawid  *        chassis.
1824588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
182508777fb0SLewanczyk, Dawid  */
18261abe55efSEd Tanous void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
18271abe55efSEd Tanous {
182855c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisData enter";
182949c53ac9SJohnathan Mantey     auto getChassisCb =
183049c53ac9SJohnathan Mantey         [SensorsAsyncResp](
183149c53ac9SJohnathan Mantey             std::shared_ptr<boost::container::flat_set<std::string>>
183208777fb0SLewanczyk, Dawid                 sensorNames) {
183355c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "getChassisCb enter";
18348fb49dd6SShawn McCarney             auto getConnectionCb = [SensorsAsyncResp, sensorNames](
18358fb49dd6SShawn McCarney                                        const boost::container::flat_set<
18368fb49dd6SShawn McCarney                                            std::string>& connections) {
183755c7b7a2SEd Tanous                 BMCWEB_LOG_DEBUG << "getConnectionCb enter";
1838de629b6eSShawn McCarney                 auto getObjectManagerPathsCb =
183949c53ac9SJohnathan Mantey                     [SensorsAsyncResp, sensorNames, connections](
18408fb49dd6SShawn McCarney                         std::shared_ptr<boost::container::flat_map<std::string,
18418fb49dd6SShawn McCarney                                                                    std::string>>
18428fb49dd6SShawn McCarney                             objectMgrPaths) {
1843de629b6eSShawn McCarney                         BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb enter";
1844*adc4f0dbSShawn McCarney                         auto getInventoryItemsCb =
1845*adc4f0dbSShawn McCarney                             [SensorsAsyncResp, sensorNames, connections,
1846*adc4f0dbSShawn McCarney                              objectMgrPaths](
1847*adc4f0dbSShawn McCarney                                 std::shared_ptr<std::vector<InventoryItem>>
1848*adc4f0dbSShawn McCarney                                     inventoryItems) {
1849*adc4f0dbSShawn McCarney                                 BMCWEB_LOG_DEBUG << "getInventoryItemsCb enter";
185049c53ac9SJohnathan Mantey                                 // Get sensor data and store results in JSON
1851de629b6eSShawn McCarney                                 getSensorData(SensorsAsyncResp, sensorNames,
1852*adc4f0dbSShawn McCarney                                               connections, objectMgrPaths,
1853*adc4f0dbSShawn McCarney                                               inventoryItems);
1854*adc4f0dbSShawn McCarney                                 BMCWEB_LOG_DEBUG << "getInventoryItemsCb exit";
1855*adc4f0dbSShawn McCarney                             };
1856*adc4f0dbSShawn McCarney 
1857*adc4f0dbSShawn McCarney                         // Get inventory items associated with sensors
1858*adc4f0dbSShawn McCarney                         getInventoryItems(SensorsAsyncResp, sensorNames,
1859*adc4f0dbSShawn McCarney                                           objectMgrPaths,
1860*adc4f0dbSShawn McCarney                                           std::move(getInventoryItemsCb));
1861*adc4f0dbSShawn McCarney 
1862de629b6eSShawn McCarney                         BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb exit";
186308777fb0SLewanczyk, Dawid                     };
1864de629b6eSShawn McCarney 
186549c53ac9SJohnathan Mantey                 // Get mapping from connection names to the DBus object
186649c53ac9SJohnathan Mantey                 // paths that implement the ObjectManager interface
1867de629b6eSShawn McCarney                 getObjectManagerPaths(SensorsAsyncResp,
1868de629b6eSShawn McCarney                                       std::move(getObjectManagerPathsCb));
186955c7b7a2SEd Tanous                 BMCWEB_LOG_DEBUG << "getConnectionCb exit";
187008777fb0SLewanczyk, Dawid             };
1871de629b6eSShawn McCarney 
1872de629b6eSShawn McCarney             // Get set of connections that provide sensor values
18731abe55efSEd Tanous             getConnections(SensorsAsyncResp, sensorNames,
18741abe55efSEd Tanous                            std::move(getConnectionCb));
187555c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "getChassisCb exit";
187608777fb0SLewanczyk, Dawid         };
18774f9a2130SJennifer Lee     SensorsAsyncResp->res.jsonValue["Redundancy"] = nlohmann::json::array();
187808777fb0SLewanczyk, Dawid 
187926f03899SShawn McCarney     // Get set of sensors in chassis
1880588c3f0dSKowalski, Kamil     getChassis(SensorsAsyncResp, std::move(getChassisCb));
188155c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisData exit";
188208777fb0SLewanczyk, Dawid };
188308777fb0SLewanczyk, Dawid 
1884413961deSRichard Marian Thomaiyar /**
188549c53ac9SJohnathan Mantey  * @brief Find the requested sensorName in the list of all sensors supplied by
188649c53ac9SJohnathan Mantey  * the chassis node
188749c53ac9SJohnathan Mantey  *
188849c53ac9SJohnathan Mantey  * @param sensorName   The sensor name supplied in the PATCH request
188949c53ac9SJohnathan Mantey  * @param sensorsList  The list of sensors managed by the chassis node
189049c53ac9SJohnathan Mantey  * @param sensorsModified  The list of sensors that were found as a result of
189149c53ac9SJohnathan Mantey  *                         repeated calls to this function
189249c53ac9SJohnathan Mantey  */
189349c53ac9SJohnathan Mantey bool findSensorNameUsingSensorPath(
18940a86febdSRichard Marian Thomaiyar     std::string_view sensorName,
189549c53ac9SJohnathan Mantey     boost::container::flat_set<std::string>& sensorsList,
189649c53ac9SJohnathan Mantey     boost::container::flat_set<std::string>& sensorsModified)
189749c53ac9SJohnathan Mantey {
18980a86febdSRichard Marian Thomaiyar     for (std::string_view chassisSensor : sensorsList)
189949c53ac9SJohnathan Mantey     {
19000a86febdSRichard Marian Thomaiyar         std::size_t pos = chassisSensor.rfind("/");
19010a86febdSRichard Marian Thomaiyar         if (pos >= (chassisSensor.size() - 1))
190249c53ac9SJohnathan Mantey         {
190349c53ac9SJohnathan Mantey             continue;
190449c53ac9SJohnathan Mantey         }
19050a86febdSRichard Marian Thomaiyar         std::string_view thisSensorName = chassisSensor.substr(pos + 1);
190649c53ac9SJohnathan Mantey         if (thisSensorName == sensorName)
190749c53ac9SJohnathan Mantey         {
190849c53ac9SJohnathan Mantey             sensorsModified.emplace(chassisSensor);
190949c53ac9SJohnathan Mantey             return true;
191049c53ac9SJohnathan Mantey         }
191149c53ac9SJohnathan Mantey     }
191249c53ac9SJohnathan Mantey     return false;
191349c53ac9SJohnathan Mantey }
191449c53ac9SJohnathan Mantey 
191549c53ac9SJohnathan Mantey /**
1916413961deSRichard Marian Thomaiyar  * @brief Entry point for overriding sensor values of given sensor
1917413961deSRichard Marian Thomaiyar  *
1918413961deSRichard Marian Thomaiyar  * @param res   response object
1919413961deSRichard Marian Thomaiyar  * @param req   request object
1920413961deSRichard Marian Thomaiyar  * @param params   parameter passed for CRUD
1921413961deSRichard Marian Thomaiyar  * @param typeList   TypeList of sensors for the resource queried
1922413961deSRichard Marian Thomaiyar  * @param chassisSubNode   Chassis Node for which the query has to happen
1923413961deSRichard Marian Thomaiyar  */
1924413961deSRichard Marian Thomaiyar void setSensorOverride(crow::Response& res, const crow::Request& req,
1925413961deSRichard Marian Thomaiyar                        const std::vector<std::string>& params,
192685e1424fSEd Tanous                        const std::vector<const char*> typeList,
1927413961deSRichard Marian Thomaiyar                        const std::string& chassisSubNode)
1928413961deSRichard Marian Thomaiyar {
1929413961deSRichard Marian Thomaiyar 
1930413961deSRichard Marian Thomaiyar     // TODO: Need to figure out dynamic way to restrict patch (Set Sensor
1931413961deSRichard Marian Thomaiyar     // override) based on another d-bus announcement to be more generic.
1932413961deSRichard Marian Thomaiyar     if (params.size() != 1)
1933413961deSRichard Marian Thomaiyar     {
1934413961deSRichard Marian Thomaiyar         messages::internalError(res);
1935413961deSRichard Marian Thomaiyar         res.end();
1936413961deSRichard Marian Thomaiyar         return;
1937413961deSRichard Marian Thomaiyar     }
1938f65af9e8SRichard Marian Thomaiyar 
1939f65af9e8SRichard Marian Thomaiyar     std::unordered_map<std::string, std::vector<nlohmann::json>> allCollections;
1940f65af9e8SRichard Marian Thomaiyar     std::optional<std::vector<nlohmann::json>> temperatureCollections;
1941f65af9e8SRichard Marian Thomaiyar     std::optional<std::vector<nlohmann::json>> fanCollections;
1942f65af9e8SRichard Marian Thomaiyar     std::vector<nlohmann::json> voltageCollections;
1943f65af9e8SRichard Marian Thomaiyar     BMCWEB_LOG_INFO << "setSensorOverride for subNode" << chassisSubNode
1944f65af9e8SRichard Marian Thomaiyar                     << "\n";
1945f65af9e8SRichard Marian Thomaiyar 
1946413961deSRichard Marian Thomaiyar     if (chassisSubNode == "Thermal")
1947413961deSRichard Marian Thomaiyar     {
1948f65af9e8SRichard Marian Thomaiyar         if (!json_util::readJson(req, res, "Temperatures",
1949f65af9e8SRichard Marian Thomaiyar                                  temperatureCollections, "Fans",
1950f65af9e8SRichard Marian Thomaiyar                                  fanCollections))
1951f65af9e8SRichard Marian Thomaiyar         {
1952f65af9e8SRichard Marian Thomaiyar             return;
1953f65af9e8SRichard Marian Thomaiyar         }
1954f65af9e8SRichard Marian Thomaiyar         if (!temperatureCollections && !fanCollections)
1955f65af9e8SRichard Marian Thomaiyar         {
1956f65af9e8SRichard Marian Thomaiyar             messages::resourceNotFound(res, "Thermal",
1957f65af9e8SRichard Marian Thomaiyar                                        "Temperatures / Voltages");
1958f65af9e8SRichard Marian Thomaiyar             res.end();
1959f65af9e8SRichard Marian Thomaiyar             return;
1960f65af9e8SRichard Marian Thomaiyar         }
1961f65af9e8SRichard Marian Thomaiyar         if (temperatureCollections)
1962f65af9e8SRichard Marian Thomaiyar         {
1963f65af9e8SRichard Marian Thomaiyar             allCollections.emplace("Temperatures",
1964f65af9e8SRichard Marian Thomaiyar                                    *std::move(temperatureCollections));
1965f65af9e8SRichard Marian Thomaiyar         }
1966f65af9e8SRichard Marian Thomaiyar         if (fanCollections)
1967f65af9e8SRichard Marian Thomaiyar         {
1968f65af9e8SRichard Marian Thomaiyar             allCollections.emplace("Fans", *std::move(fanCollections));
1969f65af9e8SRichard Marian Thomaiyar         }
1970413961deSRichard Marian Thomaiyar     }
1971413961deSRichard Marian Thomaiyar     else if (chassisSubNode == "Power")
1972413961deSRichard Marian Thomaiyar     {
1973f65af9e8SRichard Marian Thomaiyar         if (!json_util::readJson(req, res, "Voltages", voltageCollections))
1974f65af9e8SRichard Marian Thomaiyar         {
1975f65af9e8SRichard Marian Thomaiyar             return;
1976f65af9e8SRichard Marian Thomaiyar         }
1977f65af9e8SRichard Marian Thomaiyar         allCollections.emplace("Voltages", std::move(voltageCollections));
1978413961deSRichard Marian Thomaiyar     }
1979413961deSRichard Marian Thomaiyar     else
1980413961deSRichard Marian Thomaiyar     {
1981413961deSRichard Marian Thomaiyar         res.result(boost::beast::http::status::not_found);
1982413961deSRichard Marian Thomaiyar         res.end();
1983413961deSRichard Marian Thomaiyar         return;
1984413961deSRichard Marian Thomaiyar     }
1985413961deSRichard Marian Thomaiyar 
1986f65af9e8SRichard Marian Thomaiyar     const char* propertyValueName;
1987f65af9e8SRichard Marian Thomaiyar     std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
1988413961deSRichard Marian Thomaiyar     std::string memberId;
1989413961deSRichard Marian Thomaiyar     double value;
1990f65af9e8SRichard Marian Thomaiyar     for (auto& collectionItems : allCollections)
1991f65af9e8SRichard Marian Thomaiyar     {
1992f65af9e8SRichard Marian Thomaiyar         if (collectionItems.first == "Temperatures")
1993f65af9e8SRichard Marian Thomaiyar         {
1994f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingCelsius";
1995f65af9e8SRichard Marian Thomaiyar         }
1996f65af9e8SRichard Marian Thomaiyar         else if (collectionItems.first == "Fans")
1997f65af9e8SRichard Marian Thomaiyar         {
1998f65af9e8SRichard Marian Thomaiyar             propertyValueName = "Reading";
1999f65af9e8SRichard Marian Thomaiyar         }
2000f65af9e8SRichard Marian Thomaiyar         else
2001f65af9e8SRichard Marian Thomaiyar         {
2002f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingVolts";
2003f65af9e8SRichard Marian Thomaiyar         }
2004f65af9e8SRichard Marian Thomaiyar         for (auto& item : collectionItems.second)
2005f65af9e8SRichard Marian Thomaiyar         {
2006f65af9e8SRichard Marian Thomaiyar             if (!json_util::readJson(item, res, "MemberId", memberId,
2007413961deSRichard Marian Thomaiyar                                      propertyValueName, value))
2008413961deSRichard Marian Thomaiyar             {
2009413961deSRichard Marian Thomaiyar                 return;
2010413961deSRichard Marian Thomaiyar             }
2011f65af9e8SRichard Marian Thomaiyar             overrideMap.emplace(memberId,
2012f65af9e8SRichard Marian Thomaiyar                                 std::make_pair(value, collectionItems.first));
2013f65af9e8SRichard Marian Thomaiyar         }
2014f65af9e8SRichard Marian Thomaiyar     }
2015413961deSRichard Marian Thomaiyar     const std::string& chassisName = params[0];
2016413961deSRichard Marian Thomaiyar     auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
2017413961deSRichard Marian Thomaiyar         res, chassisName, typeList, chassisSubNode);
201849c53ac9SJohnathan Mantey     auto getChassisSensorListCb = [sensorAsyncResp,
201949c53ac9SJohnathan Mantey                                    overrideMap](const std::shared_ptr<
202049c53ac9SJohnathan Mantey                                                 boost::container::flat_set<
202149c53ac9SJohnathan Mantey                                                     std::string>>
202249c53ac9SJohnathan Mantey                                                     sensorsList) {
202349c53ac9SJohnathan Mantey         // Match sensor names in the PATCH request to those managed by the
202449c53ac9SJohnathan Mantey         // chassis node
202549c53ac9SJohnathan Mantey         const std::shared_ptr<boost::container::flat_set<std::string>>
202649c53ac9SJohnathan Mantey             sensorNames =
202749c53ac9SJohnathan Mantey                 std::make_shared<boost::container::flat_set<std::string>>();
2028f65af9e8SRichard Marian Thomaiyar         for (const auto& item : overrideMap)
2029413961deSRichard Marian Thomaiyar         {
2030f65af9e8SRichard Marian Thomaiyar             const auto& sensor = item.first;
203149c53ac9SJohnathan Mantey             if (!findSensorNameUsingSensorPath(sensor, *sensorsList,
203249c53ac9SJohnathan Mantey                                                *sensorNames))
2033f65af9e8SRichard Marian Thomaiyar             {
2034f65af9e8SRichard Marian Thomaiyar                 BMCWEB_LOG_INFO << "Unable to find memberId " << item.first;
2035413961deSRichard Marian Thomaiyar                 messages::resourceNotFound(sensorAsyncResp->res,
2036f65af9e8SRichard Marian Thomaiyar                                            item.second.second, item.first);
2037413961deSRichard Marian Thomaiyar                 return;
2038413961deSRichard Marian Thomaiyar             }
2039f65af9e8SRichard Marian Thomaiyar         }
2040413961deSRichard Marian Thomaiyar         // Get the connection to which the memberId belongs
2041413961deSRichard Marian Thomaiyar         auto getObjectsWithConnectionCb =
2042f65af9e8SRichard Marian Thomaiyar             [sensorAsyncResp, overrideMap](
2043413961deSRichard Marian Thomaiyar                 const boost::container::flat_set<std::string>& connections,
2044413961deSRichard Marian Thomaiyar                 const std::set<std::pair<std::string, std::string>>&
2045413961deSRichard Marian Thomaiyar                     objectsWithConnection) {
2046f65af9e8SRichard Marian Thomaiyar                 if (objectsWithConnection.size() != overrideMap.size())
2047413961deSRichard Marian Thomaiyar                 {
2048413961deSRichard Marian Thomaiyar                     BMCWEB_LOG_INFO
2049f65af9e8SRichard Marian Thomaiyar                         << "Unable to find all objects with proper connection "
2050f65af9e8SRichard Marian Thomaiyar                         << objectsWithConnection.size() << " requested "
2051f65af9e8SRichard Marian Thomaiyar                         << overrideMap.size() << "\n";
2052413961deSRichard Marian Thomaiyar                     messages::resourceNotFound(
2053413961deSRichard Marian Thomaiyar                         sensorAsyncResp->res,
2054413961deSRichard Marian Thomaiyar                         sensorAsyncResp->chassisSubNode == "Thermal"
2055413961deSRichard Marian Thomaiyar                             ? "Temperatures"
2056413961deSRichard Marian Thomaiyar                             : "Voltages",
2057f65af9e8SRichard Marian Thomaiyar                         "Count");
2058f65af9e8SRichard Marian Thomaiyar                     return;
2059f65af9e8SRichard Marian Thomaiyar                 }
2060f65af9e8SRichard Marian Thomaiyar                 for (const auto& item : objectsWithConnection)
2061f65af9e8SRichard Marian Thomaiyar                 {
2062f65af9e8SRichard Marian Thomaiyar 
2063f65af9e8SRichard Marian Thomaiyar                     auto lastPos = item.first.rfind('/');
2064f65af9e8SRichard Marian Thomaiyar                     if (lastPos == std::string::npos)
2065f65af9e8SRichard Marian Thomaiyar                     {
2066f65af9e8SRichard Marian Thomaiyar                         messages::internalError(sensorAsyncResp->res);
2067f65af9e8SRichard Marian Thomaiyar                         return;
2068f65af9e8SRichard Marian Thomaiyar                     }
2069f65af9e8SRichard Marian Thomaiyar                     std::string sensorName = item.first.substr(lastPos + 1);
2070f65af9e8SRichard Marian Thomaiyar 
2071f65af9e8SRichard Marian Thomaiyar                     const auto& iterator = overrideMap.find(sensorName);
2072f65af9e8SRichard Marian Thomaiyar                     if (iterator == overrideMap.end())
2073f65af9e8SRichard Marian Thomaiyar                     {
2074f65af9e8SRichard Marian Thomaiyar                         BMCWEB_LOG_INFO << "Unable to find sensor object"
2075f65af9e8SRichard Marian Thomaiyar                                         << item.first << "\n";
2076f65af9e8SRichard Marian Thomaiyar                         messages::internalError(sensorAsyncResp->res);
2077413961deSRichard Marian Thomaiyar                         return;
2078413961deSRichard Marian Thomaiyar                     }
2079413961deSRichard Marian Thomaiyar                     crow::connections::systemBus->async_method_call(
2080f65af9e8SRichard Marian Thomaiyar                         [sensorAsyncResp](const boost::system::error_code ec) {
2081413961deSRichard Marian Thomaiyar                             if (ec)
2082413961deSRichard Marian Thomaiyar                             {
2083413961deSRichard Marian Thomaiyar                                 BMCWEB_LOG_DEBUG
2084f65af9e8SRichard Marian Thomaiyar                                     << "setOverrideValueStatus DBUS error: "
2085413961deSRichard Marian Thomaiyar                                     << ec;
2086413961deSRichard Marian Thomaiyar                                 messages::internalError(sensorAsyncResp->res);
2087413961deSRichard Marian Thomaiyar                                 return;
2088413961deSRichard Marian Thomaiyar                             }
2089413961deSRichard Marian Thomaiyar                         },
2090f65af9e8SRichard Marian Thomaiyar                         item.second, item.first,
2091413961deSRichard Marian Thomaiyar                         "org.freedesktop.DBus.Properties", "Set",
2092413961deSRichard Marian Thomaiyar                         "xyz.openbmc_project.Sensor.Value", "Value",
2093f65af9e8SRichard Marian Thomaiyar                         sdbusplus::message::variant<double>(
2094f65af9e8SRichard Marian Thomaiyar                             iterator->second.first));
2095f65af9e8SRichard Marian Thomaiyar                 }
2096413961deSRichard Marian Thomaiyar             };
2097413961deSRichard Marian Thomaiyar         // Get object with connection for the given sensor name
2098413961deSRichard Marian Thomaiyar         getObjectsWithConnection(sensorAsyncResp, sensorNames,
2099413961deSRichard Marian Thomaiyar                                  std::move(getObjectsWithConnectionCb));
2100413961deSRichard Marian Thomaiyar     };
2101413961deSRichard Marian Thomaiyar     // get full sensor list for the given chassisId and cross verify the sensor.
2102413961deSRichard Marian Thomaiyar     getChassis(sensorAsyncResp, std::move(getChassisSensorListCb));
2103413961deSRichard Marian Thomaiyar }
2104413961deSRichard Marian Thomaiyar 
210508777fb0SLewanczyk, Dawid } // namespace redfish
2106