xref: /openbmc/bmcweb/features/redfish/lib/sensors.hpp (revision 49c53ac9b88fbf71f55076121a1605a760fa0096)
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 
31d76323e5SEd Tanous constexpr const char* dbusSensorPrefix = "/xyz/openbmc_project/sensors/";
3208777fb0SLewanczyk, Dawid 
3308777fb0SLewanczyk, Dawid using GetSubTreeType = std::vector<
3408777fb0SLewanczyk, Dawid     std::pair<std::string,
3508777fb0SLewanczyk, Dawid               std::vector<std::pair<std::string, std::vector<std::string>>>>>;
3608777fb0SLewanczyk, Dawid 
37abf2add6SEd Tanous using SensorVariant = std::variant<int64_t, double>;
38aa2e59c1SEd Tanous 
3908777fb0SLewanczyk, Dawid using ManagedObjectsVectorType = std::vector<std::pair<
40aa2e59c1SEd Tanous     sdbusplus::message::object_path,
4108777fb0SLewanczyk, Dawid     boost::container::flat_map<
42aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>>>;
4308777fb0SLewanczyk, Dawid 
4408777fb0SLewanczyk, Dawid /**
45588c3f0dSKowalski, Kamil  * SensorsAsyncResp
4608777fb0SLewanczyk, Dawid  * Gathers data needed for response processing after async calls are done
4708777fb0SLewanczyk, Dawid  */
481abe55efSEd Tanous class SensorsAsyncResp
491abe55efSEd Tanous {
5008777fb0SLewanczyk, Dawid   public:
5155c7b7a2SEd Tanous     SensorsAsyncResp(crow::Response& response, const std::string& chassisId,
52b01bf299SEd Tanous                      const std::initializer_list<const char*> types,
532474adfaSEd Tanous                      const std::string& subNode) :
5443b761d0SEd Tanous         res(response),
5543b761d0SEd Tanous         chassisId(chassisId), types(types), chassisSubNode(subNode)
561abe55efSEd Tanous     {
5708777fb0SLewanczyk, Dawid     }
5808777fb0SLewanczyk, Dawid 
591abe55efSEd Tanous     ~SensorsAsyncResp()
601abe55efSEd Tanous     {
611abe55efSEd Tanous         if (res.result() == boost::beast::http::status::internal_server_error)
621abe55efSEd Tanous         {
631abe55efSEd Tanous             // Reset the json object to clear out any data that made it in
641abe55efSEd Tanous             // before the error happened todo(ed) handle error condition with
651abe55efSEd Tanous             // proper code
6655c7b7a2SEd Tanous             res.jsonValue = nlohmann::json::object();
6708777fb0SLewanczyk, Dawid         }
6808777fb0SLewanczyk, Dawid         res.end();
6908777fb0SLewanczyk, Dawid     }
70588c3f0dSKowalski, Kamil 
7155c7b7a2SEd Tanous     crow::Response& res;
72588c3f0dSKowalski, Kamil     std::string chassisId{};
7308777fb0SLewanczyk, Dawid     const std::vector<const char*> types;
742474adfaSEd Tanous     std::string chassisSubNode{};
7508777fb0SLewanczyk, Dawid };
7608777fb0SLewanczyk, Dawid 
7708777fb0SLewanczyk, Dawid /**
78413961deSRichard Marian Thomaiyar  * @brief Get objects with connection necessary for sensors
79588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp Pointer to object holding response data
8008777fb0SLewanczyk, Dawid  * @param sensorNames Sensors retrieved from chassis
8108777fb0SLewanczyk, Dawid  * @param callback Callback for processing gathered connections
8208777fb0SLewanczyk, Dawid  */
8308777fb0SLewanczyk, Dawid template <typename Callback>
84413961deSRichard Marian Thomaiyar void getObjectsWithConnection(
85413961deSRichard Marian Thomaiyar     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
86*49c53ac9SJohnathan Mantey     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
871abe55efSEd Tanous     Callback&& callback)
881abe55efSEd Tanous {
89413961deSRichard Marian Thomaiyar     BMCWEB_LOG_DEBUG << "getObjectsWithConnection enter";
9003b5bae3SJames Feist     const std::string path = "/xyz/openbmc_project/sensors";
9108777fb0SLewanczyk, Dawid     const std::array<std::string, 1> interfaces = {
9208777fb0SLewanczyk, Dawid         "xyz.openbmc_project.Sensor.Value"};
9308777fb0SLewanczyk, Dawid 
9408777fb0SLewanczyk, Dawid     // Response handler for parsing objects subtree
951abe55efSEd Tanous     auto respHandler = [callback{std::move(callback)}, SensorsAsyncResp,
961abe55efSEd Tanous                         sensorNames](const boost::system::error_code ec,
971abe55efSEd Tanous                                      const GetSubTreeType& subtree) {
98413961deSRichard Marian Thomaiyar         BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler enter";
991abe55efSEd Tanous         if (ec)
1001abe55efSEd Tanous         {
1015f7d88c4SEd Tanous             messages::internalError(SensorsAsyncResp->res);
102413961deSRichard Marian Thomaiyar             BMCWEB_LOG_ERROR
103413961deSRichard Marian Thomaiyar                 << "getObjectsWithConnection resp_handler: Dbus error " << ec;
10408777fb0SLewanczyk, Dawid             return;
10508777fb0SLewanczyk, Dawid         }
10608777fb0SLewanczyk, Dawid 
10755c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
10808777fb0SLewanczyk, Dawid 
10908777fb0SLewanczyk, Dawid         // Make unique list of connections only for requested sensor types and
11008777fb0SLewanczyk, Dawid         // found in the chassis
11108777fb0SLewanczyk, Dawid         boost::container::flat_set<std::string> connections;
112413961deSRichard Marian Thomaiyar         std::set<std::pair<std::string, std::string>> objectsWithConnection;
1131abe55efSEd Tanous         // Intrinsic to avoid malloc.  Most systems will have < 8 sensor
1141abe55efSEd Tanous         // producers
11508777fb0SLewanczyk, Dawid         connections.reserve(8);
11608777fb0SLewanczyk, Dawid 
117*49c53ac9SJohnathan Mantey         BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames->size();
118*49c53ac9SJohnathan Mantey         for (const std::string& tsensor : *sensorNames)
1191abe55efSEd Tanous         {
12055c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor;
12108777fb0SLewanczyk, Dawid         }
12208777fb0SLewanczyk, Dawid 
12308777fb0SLewanczyk, Dawid         for (const std::pair<
12408777fb0SLewanczyk, Dawid                  std::string,
12508777fb0SLewanczyk, Dawid                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
1261abe55efSEd Tanous                  object : subtree)
1271abe55efSEd Tanous         {
128*49c53ac9SJohnathan Mantey             if (sensorNames->find(object.first) != sensorNames->end())
1291abe55efSEd Tanous             {
130*49c53ac9SJohnathan Mantey                 for (const std::pair<std::string, std::vector<std::string>>&
1311abe55efSEd Tanous                          objData : object.second)
1321abe55efSEd Tanous                 {
133*49c53ac9SJohnathan Mantey                     BMCWEB_LOG_DEBUG << "Adding connection: " << objData.first;
13408777fb0SLewanczyk, Dawid                     connections.insert(objData.first);
135de629b6eSShawn McCarney                     objectsWithConnection.insert(
136de629b6eSShawn McCarney                         std::make_pair(object.first, objData.first));
13708777fb0SLewanczyk, Dawid                 }
13808777fb0SLewanczyk, Dawid             }
13908777fb0SLewanczyk, Dawid         }
14055c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections";
141413961deSRichard Marian Thomaiyar         callback(std::move(connections), std::move(objectsWithConnection));
142413961deSRichard Marian Thomaiyar         BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler exit";
14308777fb0SLewanczyk, Dawid     };
14408777fb0SLewanczyk, Dawid     // Make call to ObjectMapper to find all sensors objects
14555c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
14655c7b7a2SEd Tanous         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
1471abe55efSEd Tanous         "/xyz/openbmc_project/object_mapper",
1481abe55efSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 2, interfaces);
149413961deSRichard Marian Thomaiyar     BMCWEB_LOG_DEBUG << "getObjectsWithConnection exit";
150413961deSRichard Marian Thomaiyar }
151413961deSRichard Marian Thomaiyar 
152413961deSRichard Marian Thomaiyar /**
153413961deSRichard Marian Thomaiyar  * @brief Create connections necessary for sensors
154413961deSRichard Marian Thomaiyar  * @param SensorsAsyncResp Pointer to object holding response data
155413961deSRichard Marian Thomaiyar  * @param sensorNames Sensors retrieved from chassis
156413961deSRichard Marian Thomaiyar  * @param callback Callback for processing gathered connections
157413961deSRichard Marian Thomaiyar  */
158413961deSRichard Marian Thomaiyar template <typename Callback>
159*49c53ac9SJohnathan Mantey void getConnections(
160*49c53ac9SJohnathan Mantey     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
161*49c53ac9SJohnathan Mantey     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
162413961deSRichard Marian Thomaiyar     Callback&& callback)
163413961deSRichard Marian Thomaiyar {
164413961deSRichard Marian Thomaiyar     auto objectsWithConnectionCb =
165413961deSRichard Marian Thomaiyar         [callback](const boost::container::flat_set<std::string>& connections,
166413961deSRichard Marian Thomaiyar                    const std::set<std::pair<std::string, std::string>>&
167413961deSRichard Marian Thomaiyar                        objectsWithConnection) {
168413961deSRichard Marian Thomaiyar             callback(std::move(connections));
169413961deSRichard Marian Thomaiyar         };
170413961deSRichard Marian Thomaiyar     getObjectsWithConnection(SensorsAsyncResp, sensorNames,
171413961deSRichard Marian Thomaiyar                              std::move(objectsWithConnectionCb));
17208777fb0SLewanczyk, Dawid }
17308777fb0SLewanczyk, Dawid 
17408777fb0SLewanczyk, Dawid /**
175de629b6eSShawn McCarney  * @brief Gets all DBus sensor names.
176de629b6eSShawn McCarney  *
177de629b6eSShawn McCarney  * Finds the sensor names asynchronously.  Invokes callback when information has
178de629b6eSShawn McCarney  * been obtained.
179de629b6eSShawn McCarney  *
180de629b6eSShawn McCarney  * The callback must have the following signature:
181de629b6eSShawn McCarney  *   @code
182de629b6eSShawn McCarney  *   callback(boost::container::flat_set<std::string>& sensorNames)
183de629b6eSShawn McCarney  *   @endcode
184de629b6eSShawn McCarney  *
185de629b6eSShawn McCarney  * @param SensorsAsyncResp Pointer to object holding response data.
186de629b6eSShawn McCarney  * @param callback Callback to invoke when sensor names obtained.
187de629b6eSShawn McCarney  */
188de629b6eSShawn McCarney template <typename Callback>
189de629b6eSShawn McCarney void getAllSensors(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
190de629b6eSShawn McCarney                    Callback&& callback)
191de629b6eSShawn McCarney {
192de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getAllSensors enter";
193de629b6eSShawn McCarney     const std::array<std::string, 1> interfaces = {
194de629b6eSShawn McCarney         "xyz.openbmc_project.Sensor.Value"};
195de629b6eSShawn McCarney 
196de629b6eSShawn McCarney     // Response handler for GetSubTreePaths DBus method
197de629b6eSShawn McCarney     auto respHandler = [callback{std::move(callback)}, SensorsAsyncResp](
198de629b6eSShawn McCarney                            const boost::system::error_code ec,
199de629b6eSShawn McCarney                            const std::vector<std::string>& sensorList) {
200de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "getAllSensors respHandler enter";
201de629b6eSShawn McCarney         if (ec)
202de629b6eSShawn McCarney         {
203de629b6eSShawn McCarney             messages::internalError(SensorsAsyncResp->res);
204de629b6eSShawn McCarney             BMCWEB_LOG_ERROR << "getAllSensors respHandler: DBus error " << ec;
205de629b6eSShawn McCarney             return;
206de629b6eSShawn McCarney         }
207de629b6eSShawn McCarney         boost::container::flat_set<std::string> sensorNames;
208de629b6eSShawn McCarney         for (const std::string& sensor : sensorList)
209de629b6eSShawn McCarney         {
210de629b6eSShawn McCarney             std::size_t lastPos = sensor.rfind("/");
211de629b6eSShawn McCarney             if (lastPos == std::string::npos)
212de629b6eSShawn McCarney             {
213de629b6eSShawn McCarney                 BMCWEB_LOG_ERROR << "Failed to find '/' in " << sensor;
214de629b6eSShawn McCarney                 continue;
215de629b6eSShawn McCarney             }
216de629b6eSShawn McCarney             std::string sensorName = sensor.substr(lastPos + 1);
217de629b6eSShawn McCarney             sensorNames.emplace(sensorName);
218de629b6eSShawn McCarney             BMCWEB_LOG_DEBUG << "Added sensor name " << sensorName;
219de629b6eSShawn McCarney         }
220de629b6eSShawn McCarney         callback(sensorNames);
221de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "getAllSensors respHandler exit";
222de629b6eSShawn McCarney     };
223de629b6eSShawn McCarney 
224de629b6eSShawn McCarney     // Query mapper for all DBus sensor object paths
225de629b6eSShawn McCarney     crow::connections::systemBus->async_method_call(
226de629b6eSShawn McCarney         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
227de629b6eSShawn McCarney         "/xyz/openbmc_project/object_mapper",
228de629b6eSShawn McCarney         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
229de629b6eSShawn McCarney         "/xyz/openbmc_project/sensors", int32_t(0), interfaces);
230de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getAllSensors exit";
231de629b6eSShawn McCarney }
232de629b6eSShawn McCarney 
233de629b6eSShawn McCarney /**
234*49c53ac9SJohnathan Mantey  * @brief Shrinks the list of sensors for processing
235*49c53ac9SJohnathan Mantey  * @param SensorsAysncResp  The class holding the Redfish response
236*49c53ac9SJohnathan Mantey  * @param allSensors  A list of all the sensors associated to the
237*49c53ac9SJohnathan Mantey  * chassis element (i.e. baseboard, front panel, etc...)
238*49c53ac9SJohnathan Mantey  * @param activeSensors A list that is a reduction of the incoming
239*49c53ac9SJohnathan Mantey  * allSensors list.  Eliminate Thermal sensors when a Power request is
240*49c53ac9SJohnathan Mantey  * made, and eliminate Power sensors when a Thermal request is made.
241*49c53ac9SJohnathan Mantey  */
242*49c53ac9SJohnathan Mantey void reduceSensorList(
243*49c53ac9SJohnathan Mantey     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
244*49c53ac9SJohnathan Mantey     const std::vector<std::string>* allSensors,
245*49c53ac9SJohnathan Mantey     std::shared_ptr<boost::container::flat_set<std::string>> activeSensors)
246*49c53ac9SJohnathan Mantey {
247*49c53ac9SJohnathan Mantey     if (SensorsAsyncResp == nullptr)
248*49c53ac9SJohnathan Mantey     {
249*49c53ac9SJohnathan Mantey         return;
250*49c53ac9SJohnathan Mantey     }
251*49c53ac9SJohnathan Mantey     if ((allSensors == nullptr) || (activeSensors == nullptr))
252*49c53ac9SJohnathan Mantey     {
253*49c53ac9SJohnathan Mantey         messages::resourceNotFound(
254*49c53ac9SJohnathan Mantey             SensorsAsyncResp->res, SensorsAsyncResp->chassisSubNode,
255*49c53ac9SJohnathan Mantey             SensorsAsyncResp->chassisSubNode == "Thermal" ? "Temperatures"
256*49c53ac9SJohnathan Mantey                                                           : "Voltages");
257*49c53ac9SJohnathan Mantey 
258*49c53ac9SJohnathan Mantey         return;
259*49c53ac9SJohnathan Mantey     }
260*49c53ac9SJohnathan Mantey     if (allSensors->empty())
261*49c53ac9SJohnathan Mantey     {
262*49c53ac9SJohnathan Mantey         // Nothing to do, the activeSensors object is also empty
263*49c53ac9SJohnathan Mantey         return;
264*49c53ac9SJohnathan Mantey     }
265*49c53ac9SJohnathan Mantey 
266*49c53ac9SJohnathan Mantey     for (const char* type : SensorsAsyncResp->types)
267*49c53ac9SJohnathan Mantey     {
268*49c53ac9SJohnathan Mantey         for (const std::string& sensor : *allSensors)
269*49c53ac9SJohnathan Mantey         {
270*49c53ac9SJohnathan Mantey             if (boost::starts_with(sensor, type))
271*49c53ac9SJohnathan Mantey             {
272*49c53ac9SJohnathan Mantey                 activeSensors->emplace(sensor);
273*49c53ac9SJohnathan Mantey             }
274*49c53ac9SJohnathan Mantey         }
275*49c53ac9SJohnathan Mantey     }
276*49c53ac9SJohnathan Mantey }
277*49c53ac9SJohnathan Mantey 
278*49c53ac9SJohnathan Mantey /**
27908777fb0SLewanczyk, Dawid  * @brief Retrieves requested chassis sensors and redundancy data from DBus .
280588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
28108777fb0SLewanczyk, Dawid  * @param callback  Callback for next step in gathered sensor processing
28208777fb0SLewanczyk, Dawid  */
28308777fb0SLewanczyk, Dawid template <typename Callback>
284*49c53ac9SJohnathan Mantey void getChassis(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
2851abe55efSEd Tanous                 Callback&& callback)
2861abe55efSEd Tanous {
28755c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis enter";
288*49c53ac9SJohnathan Mantey     const std::array<const char*, 3> interfaces = {
289*49c53ac9SJohnathan Mantey         "xyz.openbmc_project.Inventory.Item.Board",
290*49c53ac9SJohnathan Mantey         "xyz.openbmc_project.Inventory.Item.Chassis",
291*49c53ac9SJohnathan Mantey         "xyz.openbmc_project.Inventory.Item.PowerSupply"};
292*49c53ac9SJohnathan Mantey     auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp](
293*49c53ac9SJohnathan Mantey                            const boost::system::error_code ec,
294*49c53ac9SJohnathan Mantey                            const std::vector<std::string>& chassisPaths) {
29555c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassis respHandler enter";
2961abe55efSEd Tanous         if (ec)
2971abe55efSEd Tanous         {
29855c7b7a2SEd Tanous             BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec;
299*49c53ac9SJohnathan Mantey             messages::internalError(sensorsAsyncResp->res);
30008777fb0SLewanczyk, Dawid             return;
30108777fb0SLewanczyk, Dawid         }
30208777fb0SLewanczyk, Dawid 
303*49c53ac9SJohnathan Mantey         const std::string* chassisPath = nullptr;
304*49c53ac9SJohnathan Mantey         std::string chassisName;
305*49c53ac9SJohnathan Mantey         for (const std::string& chassis : chassisPaths)
3061abe55efSEd Tanous         {
307*49c53ac9SJohnathan Mantey             std::size_t lastPos = chassis.rfind("/");
308*49c53ac9SJohnathan Mantey             if (lastPos == std::string::npos)
3091abe55efSEd Tanous             {
310*49c53ac9SJohnathan Mantey                 BMCWEB_LOG_ERROR << "Failed to find '/' in " << chassis;
311daf36e2eSEd Tanous                 continue;
312daf36e2eSEd Tanous             }
313*49c53ac9SJohnathan Mantey             chassisName = chassis.substr(lastPos + 1);
314*49c53ac9SJohnathan Mantey             if (chassisName == sensorsAsyncResp->chassisId)
3151abe55efSEd Tanous             {
316*49c53ac9SJohnathan Mantey                 chassisPath = &chassis;
317*49c53ac9SJohnathan Mantey                 break;
318daf36e2eSEd Tanous             }
319*49c53ac9SJohnathan Mantey         }
320*49c53ac9SJohnathan Mantey         if (chassisPath == nullptr)
3211abe55efSEd Tanous         {
322*49c53ac9SJohnathan Mantey             messages::resourceNotFound(sensorsAsyncResp->res, "Chassis",
323*49c53ac9SJohnathan Mantey                                        sensorsAsyncResp->chassisId);
324*49c53ac9SJohnathan Mantey             return;
3251abe55efSEd Tanous         }
32608777fb0SLewanczyk, Dawid 
327*49c53ac9SJohnathan Mantey         const std::string& chassisSubNode = sensorsAsyncResp->chassisSubNode;
328*49c53ac9SJohnathan Mantey         if (chassisSubNode == "Power")
329*49c53ac9SJohnathan Mantey         {
330*49c53ac9SJohnathan Mantey             sensorsAsyncResp->res.jsonValue["@odata.type"] =
331*49c53ac9SJohnathan Mantey                 "#Power.v1_5_2.Power";
332*49c53ac9SJohnathan Mantey         }
333*49c53ac9SJohnathan Mantey         else if (chassisSubNode == "Thermal")
334*49c53ac9SJohnathan Mantey         {
335*49c53ac9SJohnathan Mantey             sensorsAsyncResp->res.jsonValue["@odata.type"] =
336*49c53ac9SJohnathan Mantey                 "#Thermal.v1_4_0.Thermal";
337*49c53ac9SJohnathan Mantey         }
338*49c53ac9SJohnathan Mantey         sensorsAsyncResp->res.jsonValue["@odata.id"] =
339*49c53ac9SJohnathan Mantey             "/redfish/v1/Chassis/" + sensorsAsyncResp->chassisId + "/" +
340*49c53ac9SJohnathan Mantey             chassisSubNode;
341*49c53ac9SJohnathan Mantey 
342*49c53ac9SJohnathan Mantey         sensorsAsyncResp->res.jsonValue["@odata.context"] =
343*49c53ac9SJohnathan Mantey             "/redfish/v1/$metadata#" + chassisSubNode + "." + chassisSubNode;
344*49c53ac9SJohnathan Mantey         sensorsAsyncResp->res.jsonValue["Id"] = chassisSubNode;
345*49c53ac9SJohnathan Mantey         sensorsAsyncResp->res.jsonValue["Name"] = chassisSubNode;
346*49c53ac9SJohnathan Mantey 
347*49c53ac9SJohnathan Mantey         // Get the list of sensors for this Chassis element
348*49c53ac9SJohnathan Mantey         std::string sensorPath = *chassisPath + "/sensors";
34955c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
350*49c53ac9SJohnathan Mantey             [sensorsAsyncResp, callback{std::move(callback)}](
351*49c53ac9SJohnathan Mantey                 const boost::system::error_code ec,
352*49c53ac9SJohnathan Mantey                 const std::variant<std::vector<std::string>>&
353*49c53ac9SJohnathan Mantey                     variantEndpoints) {
354*49c53ac9SJohnathan Mantey                 if (ec)
355*49c53ac9SJohnathan Mantey                 {
356*49c53ac9SJohnathan Mantey                     if (ec.value() != EBADR)
357*49c53ac9SJohnathan Mantey                     {
358*49c53ac9SJohnathan Mantey                         messages::internalError(sensorsAsyncResp->res);
359*49c53ac9SJohnathan Mantey                         return;
360*49c53ac9SJohnathan Mantey                     }
361*49c53ac9SJohnathan Mantey                 }
362*49c53ac9SJohnathan Mantey                 const std::vector<std::string>* nodeSensorList =
363*49c53ac9SJohnathan Mantey                     std::get_if<std::vector<std::string>>(&(variantEndpoints));
364*49c53ac9SJohnathan Mantey                 if (nodeSensorList == nullptr)
365*49c53ac9SJohnathan Mantey                 {
366*49c53ac9SJohnathan Mantey                     messages::resourceNotFound(
367*49c53ac9SJohnathan Mantey                         sensorsAsyncResp->res, sensorsAsyncResp->chassisSubNode,
368*49c53ac9SJohnathan Mantey                         sensorsAsyncResp->chassisSubNode == "Thermal"
369*49c53ac9SJohnathan Mantey                             ? "Temperatures"
370*49c53ac9SJohnathan Mantey                             : "Voltages");
371*49c53ac9SJohnathan Mantey                     return;
372*49c53ac9SJohnathan Mantey                 }
373*49c53ac9SJohnathan Mantey                 const std::shared_ptr<boost::container::flat_set<std::string>>
374*49c53ac9SJohnathan Mantey                     culledSensorList = std::make_shared<
375*49c53ac9SJohnathan Mantey                         boost::container::flat_set<std::string>>();
376*49c53ac9SJohnathan Mantey                 reduceSensorList(sensorsAsyncResp, nodeSensorList,
377*49c53ac9SJohnathan Mantey                                  culledSensorList);
378*49c53ac9SJohnathan Mantey                 callback(culledSensorList);
379*49c53ac9SJohnathan Mantey             },
380*49c53ac9SJohnathan Mantey             "xyz.openbmc_project.ObjectMapper", sensorPath,
381*49c53ac9SJohnathan Mantey             "org.freedesktop.DBus.Properties", "Get",
382*49c53ac9SJohnathan Mantey             "xyz.openbmc_project.Association", "endpoints");
383*49c53ac9SJohnathan Mantey     };
384*49c53ac9SJohnathan Mantey 
385*49c53ac9SJohnathan Mantey     // Get the Chassis Collection
386*49c53ac9SJohnathan Mantey     crow::connections::systemBus->async_method_call(
387*49c53ac9SJohnathan Mantey         respHandler, "xyz.openbmc_project.ObjectMapper",
388*49c53ac9SJohnathan Mantey         "/xyz/openbmc_project/object_mapper",
389*49c53ac9SJohnathan Mantey         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
390*49c53ac9SJohnathan Mantey         "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
39155c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis exit";
39208777fb0SLewanczyk, Dawid }
39308777fb0SLewanczyk, Dawid 
39408777fb0SLewanczyk, Dawid /**
395de629b6eSShawn McCarney  * @brief Finds all DBus object paths that implement ObjectManager.
396de629b6eSShawn McCarney  *
397de629b6eSShawn McCarney  * Creates a mapping from the associated connection name to the object path.
398de629b6eSShawn McCarney  *
399de629b6eSShawn McCarney  * Finds the object paths asynchronously.  Invokes callback when information has
400de629b6eSShawn McCarney  * been obtained.
401de629b6eSShawn McCarney  *
402de629b6eSShawn McCarney  * The callback must have the following signature:
403de629b6eSShawn McCarney  *   @code
404de629b6eSShawn McCarney  *   callback(const boost::container::flat_map<std::string,
405de629b6eSShawn McCarney  *            std::string>& objectMgrPaths)
406de629b6eSShawn McCarney  *   @endcode
407de629b6eSShawn McCarney  *
408*49c53ac9SJohnathan Mantey  * @param sensorsAsyncResp Pointer to object holding response data.
409de629b6eSShawn McCarney  * @param callback Callback to invoke when object paths obtained.
410de629b6eSShawn McCarney  */
411de629b6eSShawn McCarney template <typename Callback>
412de629b6eSShawn McCarney void getObjectManagerPaths(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
413de629b6eSShawn McCarney                            Callback&& callback)
414de629b6eSShawn McCarney {
415de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getObjectManagerPaths enter";
416de629b6eSShawn McCarney     const std::array<std::string, 1> interfaces = {
417de629b6eSShawn McCarney         "org.freedesktop.DBus.ObjectManager"};
418de629b6eSShawn McCarney 
419de629b6eSShawn McCarney     // Response handler for GetSubTree DBus method
420de629b6eSShawn McCarney     auto respHandler = [callback{std::move(callback)},
421de629b6eSShawn McCarney                         SensorsAsyncResp](const boost::system::error_code ec,
422de629b6eSShawn McCarney                                           const GetSubTreeType& subtree) {
423de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler enter";
424de629b6eSShawn McCarney         if (ec)
425de629b6eSShawn McCarney         {
426de629b6eSShawn McCarney             messages::internalError(SensorsAsyncResp->res);
427de629b6eSShawn McCarney             BMCWEB_LOG_ERROR << "getObjectManagerPaths respHandler: DBus error "
428de629b6eSShawn McCarney                              << ec;
429de629b6eSShawn McCarney             return;
430de629b6eSShawn McCarney         }
431de629b6eSShawn McCarney 
432de629b6eSShawn McCarney         // Loop over returned object paths
433de629b6eSShawn McCarney         boost::container::flat_map<std::string, std::string> objectMgrPaths;
434de629b6eSShawn McCarney         for (const std::pair<
435de629b6eSShawn McCarney                  std::string,
436de629b6eSShawn McCarney                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
437de629b6eSShawn McCarney                  object : subtree)
438de629b6eSShawn McCarney         {
439de629b6eSShawn McCarney             // Loop over connections for current object path
440de629b6eSShawn McCarney             const std::string& objectPath = object.first;
441de629b6eSShawn McCarney             for (const std::pair<std::string, std::vector<std::string>>&
442de629b6eSShawn McCarney                      objData : object.second)
443de629b6eSShawn McCarney             {
444de629b6eSShawn McCarney                 // Add mapping from connection to object path
445de629b6eSShawn McCarney                 const std::string& connection = objData.first;
446de629b6eSShawn McCarney                 objectMgrPaths[connection] = objectPath;
447de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "Added mapping " << connection << " -> "
448de629b6eSShawn McCarney                                  << objectPath;
449de629b6eSShawn McCarney             }
450de629b6eSShawn McCarney         }
451de629b6eSShawn McCarney         callback(std::move(objectMgrPaths));
452de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler exit";
453de629b6eSShawn McCarney     };
454de629b6eSShawn McCarney 
455de629b6eSShawn McCarney     // Query mapper for all DBus object paths that implement ObjectManager
456de629b6eSShawn McCarney     crow::connections::systemBus->async_method_call(
457de629b6eSShawn McCarney         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
458de629b6eSShawn McCarney         "/xyz/openbmc_project/object_mapper",
459de629b6eSShawn McCarney         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
460de629b6eSShawn McCarney         interfaces);
461de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getObjectManagerPaths exit";
462de629b6eSShawn McCarney }
463de629b6eSShawn McCarney 
464de629b6eSShawn McCarney /**
46508777fb0SLewanczyk, Dawid  * @brief Builds a json sensor representation of a sensor.
46608777fb0SLewanczyk, Dawid  * @param sensorName  The name of the sensor to be built
467274fad5aSGunnar Mills  * @param sensorType  The type (temperature, fan_tach, etc) of the sensor to
46808777fb0SLewanczyk, Dawid  * build
46908777fb0SLewanczyk, Dawid  * @param interfacesDict  A dictionary of the interfaces and properties of said
47008777fb0SLewanczyk, Dawid  * interfaces to be built from
47108777fb0SLewanczyk, Dawid  * @param sensor_json  The json object to fill
47208777fb0SLewanczyk, Dawid  */
47308777fb0SLewanczyk, Dawid void objectInterfacesToJson(
47408777fb0SLewanczyk, Dawid     const std::string& sensorName, const std::string& sensorType,
47508777fb0SLewanczyk, Dawid     const boost::container::flat_map<
476aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>&
47708777fb0SLewanczyk, Dawid         interfacesDict,
4781abe55efSEd Tanous     nlohmann::json& sensor_json)
4791abe55efSEd Tanous {
48008777fb0SLewanczyk, Dawid     // We need a value interface before we can do anything with it
48155c7b7a2SEd Tanous     auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
4821abe55efSEd Tanous     if (valueIt == interfacesDict.end())
4831abe55efSEd Tanous     {
48455c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface";
48508777fb0SLewanczyk, Dawid         return;
48608777fb0SLewanczyk, Dawid     }
48708777fb0SLewanczyk, Dawid 
48808777fb0SLewanczyk, Dawid     // Assume values exist as is (10^0 == 1) if no scale exists
48908777fb0SLewanczyk, Dawid     int64_t scaleMultiplier = 0;
49008777fb0SLewanczyk, Dawid 
49155c7b7a2SEd Tanous     auto scaleIt = valueIt->second.find("Scale");
49208777fb0SLewanczyk, Dawid     // If a scale exists, pull value as int64, and use the scaling.
4931abe55efSEd Tanous     if (scaleIt != valueIt->second.end())
4941abe55efSEd Tanous     {
495abf2add6SEd Tanous         const int64_t* int64Value = std::get_if<int64_t>(&scaleIt->second);
4961abe55efSEd Tanous         if (int64Value != nullptr)
4971abe55efSEd Tanous         {
49808777fb0SLewanczyk, Dawid             scaleMultiplier = *int64Value;
49908777fb0SLewanczyk, Dawid         }
50008777fb0SLewanczyk, Dawid     }
50108777fb0SLewanczyk, Dawid 
50208777fb0SLewanczyk, Dawid     sensor_json["MemberId"] = sensorName;
50308777fb0SLewanczyk, Dawid     sensor_json["Name"] = sensorName;
50408777fb0SLewanczyk, Dawid     sensor_json["Status"]["State"] = "Enabled";
50508777fb0SLewanczyk, Dawid     sensor_json["Status"]["Health"] = "OK";
50608777fb0SLewanczyk, Dawid 
50708777fb0SLewanczyk, Dawid     // Parameter to set to override the type we get from dbus, and force it to
50808777fb0SLewanczyk, Dawid     // int, regardless of what is available.  This is used for schemas like fan,
50908777fb0SLewanczyk, Dawid     // that require integers, not floats.
51008777fb0SLewanczyk, Dawid     bool forceToInt = false;
51108777fb0SLewanczyk, Dawid 
51208777fb0SLewanczyk, Dawid     const char* unit = "Reading";
5131abe55efSEd Tanous     if (sensorType == "temperature")
5141abe55efSEd Tanous     {
51508777fb0SLewanczyk, Dawid         unit = "ReadingCelsius";
5167885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature";
51708777fb0SLewanczyk, Dawid         // TODO(ed) Documentation says that path should be type fan_tach,
51808777fb0SLewanczyk, Dawid         // implementation seems to implement fan
5191abe55efSEd Tanous     }
5201abe55efSEd Tanous     else if (sensorType == "fan" || sensorType == "fan_tach")
5211abe55efSEd Tanous     {
52208777fb0SLewanczyk, Dawid         unit = "Reading";
52308777fb0SLewanczyk, Dawid         sensor_json["ReadingUnits"] = "RPM";
5247885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
52508777fb0SLewanczyk, Dawid         forceToInt = true;
5261abe55efSEd Tanous     }
5276f6d0d32SEd Tanous     else if (sensorType == "fan_pwm")
5286f6d0d32SEd Tanous     {
5296f6d0d32SEd Tanous         unit = "Reading";
5306f6d0d32SEd Tanous         sensor_json["ReadingUnits"] = "Percent";
5316f6d0d32SEd Tanous         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
5326f6d0d32SEd Tanous         forceToInt = true;
5336f6d0d32SEd Tanous     }
5341abe55efSEd Tanous     else if (sensorType == "voltage")
5351abe55efSEd Tanous     {
53608777fb0SLewanczyk, Dawid         unit = "ReadingVolts";
5377885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage";
5381abe55efSEd Tanous     }
5392474adfaSEd Tanous     else if (sensorType == "power")
5402474adfaSEd Tanous     {
541*49c53ac9SJohnathan Mantey         std::string sensorNameLower =
542*49c53ac9SJohnathan Mantey             boost::algorithm::to_lower_copy(sensorName);
543*49c53ac9SJohnathan Mantey 
544*49c53ac9SJohnathan Mantey         if (sensorNameLower.find("input") != std::string::npos)
545*49c53ac9SJohnathan Mantey         {
546*49c53ac9SJohnathan Mantey             unit = "PowerInputWatts";
547*49c53ac9SJohnathan Mantey         }
548*49c53ac9SJohnathan Mantey         else
549*49c53ac9SJohnathan Mantey         {
550*49c53ac9SJohnathan Mantey             unit = "PowerOutputWatts";
551*49c53ac9SJohnathan Mantey         }
5522474adfaSEd Tanous     }
5531abe55efSEd Tanous     else
5541abe55efSEd Tanous     {
55555c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
55608777fb0SLewanczyk, Dawid         return;
55708777fb0SLewanczyk, Dawid     }
55808777fb0SLewanczyk, Dawid     // Map of dbus interface name, dbus property name and redfish property_name
55908777fb0SLewanczyk, Dawid     std::vector<std::tuple<const char*, const char*, const char*>> properties;
56008777fb0SLewanczyk, Dawid     properties.reserve(7);
56108777fb0SLewanczyk, Dawid 
56208777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
563de629b6eSShawn McCarney 
564de629b6eSShawn McCarney     // If sensor type doesn't map to Redfish PowerSupply, add threshold props
565de629b6eSShawn McCarney     if ((sensorType != "current") && (sensorType != "power"))
566de629b6eSShawn McCarney     {
56708777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
56808777fb0SLewanczyk, Dawid                                 "WarningHigh", "UpperThresholdNonCritical");
56908777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
57008777fb0SLewanczyk, Dawid                                 "WarningLow", "LowerThresholdNonCritical");
57108777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
57208777fb0SLewanczyk, Dawid                                 "CriticalHigh", "UpperThresholdCritical");
57308777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
57408777fb0SLewanczyk, Dawid                                 "CriticalLow", "LowerThresholdCritical");
575de629b6eSShawn McCarney     }
57608777fb0SLewanczyk, Dawid 
5772474adfaSEd Tanous     // TODO Need to get UpperThresholdFatal and LowerThresholdFatal
5782474adfaSEd Tanous 
5791abe55efSEd Tanous     if (sensorType == "temperature")
5801abe55efSEd Tanous     {
58108777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
58208777fb0SLewanczyk, Dawid                                 "MinReadingRangeTemp");
58308777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
58408777fb0SLewanczyk, Dawid                                 "MaxReadingRangeTemp");
5851abe55efSEd Tanous     }
586de629b6eSShawn McCarney     else if ((sensorType != "current") && (sensorType != "power"))
5871abe55efSEd Tanous     {
588de629b6eSShawn McCarney         // Sensor type doesn't map to Redfish PowerSupply; add min/max props
58908777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
59008777fb0SLewanczyk, Dawid                                 "MinReadingRange");
59108777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
59208777fb0SLewanczyk, Dawid                                 "MaxReadingRange");
59308777fb0SLewanczyk, Dawid     }
59408777fb0SLewanczyk, Dawid 
59508777fb0SLewanczyk, Dawid     for (const std::tuple<const char*, const char*, const char*>& p :
5961abe55efSEd Tanous          properties)
5971abe55efSEd Tanous     {
59808777fb0SLewanczyk, Dawid         auto interfaceProperties = interfacesDict.find(std::get<0>(p));
5991abe55efSEd Tanous         if (interfaceProperties != interfacesDict.end())
6001abe55efSEd Tanous         {
601b01bf299SEd Tanous             auto valueIt = interfaceProperties->second.find(std::get<1>(p));
602b01bf299SEd Tanous             if (valueIt != interfaceProperties->second.end())
6031abe55efSEd Tanous             {
604b01bf299SEd Tanous                 const SensorVariant& valueVariant = valueIt->second;
605b01bf299SEd Tanous                 nlohmann::json& valueIt = sensor_json[std::get<2>(p)];
60608777fb0SLewanczyk, Dawid                 // Attempt to pull the int64 directly
607abf2add6SEd Tanous                 const int64_t* int64Value = std::get_if<int64_t>(&valueVariant);
60808777fb0SLewanczyk, Dawid 
609abf2add6SEd Tanous                 const double* doubleValue = std::get_if<double>(&valueVariant);
6106f6d0d32SEd Tanous                 double temp = 0.0;
6116f6d0d32SEd Tanous                 if (int64Value != nullptr)
6121abe55efSEd Tanous                 {
6136f6d0d32SEd Tanous                     temp = *int64Value;
6146f6d0d32SEd Tanous                 }
6156f6d0d32SEd Tanous                 else if (doubleValue != nullptr)
6161abe55efSEd Tanous                 {
6176f6d0d32SEd Tanous                     temp = *doubleValue;
6181abe55efSEd Tanous                 }
6191abe55efSEd Tanous                 else
6201abe55efSEd Tanous                 {
6216f6d0d32SEd Tanous                     BMCWEB_LOG_ERROR
6226f6d0d32SEd Tanous                         << "Got value interface that wasn't int or double";
6236f6d0d32SEd Tanous                     continue;
62408777fb0SLewanczyk, Dawid                 }
6256f6d0d32SEd Tanous                 temp = temp * std::pow(10, scaleMultiplier);
6266f6d0d32SEd Tanous                 if (forceToInt)
6276f6d0d32SEd Tanous                 {
628b01bf299SEd Tanous                     valueIt = static_cast<int64_t>(temp);
6296f6d0d32SEd Tanous                 }
6306f6d0d32SEd Tanous                 else
6316f6d0d32SEd Tanous                 {
632b01bf299SEd Tanous                     valueIt = temp;
63308777fb0SLewanczyk, Dawid                 }
63408777fb0SLewanczyk, Dawid             }
63508777fb0SLewanczyk, Dawid         }
63608777fb0SLewanczyk, Dawid     }
63755c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
63808777fb0SLewanczyk, Dawid }
63908777fb0SLewanczyk, Dawid 
6408bd25ccdSJames Feist static void
6418bd25ccdSJames Feist     populateFanRedundancy(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp)
6428bd25ccdSJames Feist {
6438bd25ccdSJames Feist     crow::connections::systemBus->async_method_call(
6448bd25ccdSJames Feist         [sensorsAsyncResp](const boost::system::error_code ec,
6458bd25ccdSJames Feist                            const GetSubTreeType& resp) {
6468bd25ccdSJames Feist             if (ec)
6478bd25ccdSJames Feist             {
6488bd25ccdSJames Feist                 return; // don't have to have this interface
6498bd25ccdSJames Feist             }
650e278c18fSEd Tanous             for (const std::pair<std::string,
651e278c18fSEd Tanous                                  std::vector<std::pair<
652e278c18fSEd Tanous                                      std::string, std::vector<std::string>>>>&
653e278c18fSEd Tanous                      pathPair : resp)
6548bd25ccdSJames Feist             {
655e278c18fSEd Tanous                 const std::string& path = pathPair.first;
656e278c18fSEd Tanous                 const std::vector<
657e278c18fSEd Tanous                     std::pair<std::string, std::vector<std::string>>>& objDict =
658e278c18fSEd Tanous                     pathPair.second;
6598bd25ccdSJames Feist                 if (objDict.empty())
6608bd25ccdSJames Feist                 {
6618bd25ccdSJames Feist                     continue; // this should be impossible
6628bd25ccdSJames Feist                 }
6638bd25ccdSJames Feist 
6648bd25ccdSJames Feist                 const std::string& owner = objDict.begin()->first;
6658bd25ccdSJames Feist                 crow::connections::systemBus->async_method_call(
6668bd25ccdSJames Feist                     [path, owner,
6678bd25ccdSJames Feist                      sensorsAsyncResp](const boost::system::error_code ec,
6688bd25ccdSJames Feist                                        std::variant<std::vector<std::string>>
6698bd25ccdSJames Feist                                            variantEndpoints) {
6708bd25ccdSJames Feist                         if (ec)
6718bd25ccdSJames Feist                         {
6728bd25ccdSJames Feist                             return; // if they don't have an association we
6738bd25ccdSJames Feist                                     // can't tell what chassis is
6748bd25ccdSJames Feist                         }
6758bd25ccdSJames Feist                         // verify part of the right chassis
6768bd25ccdSJames Feist                         auto endpoints = std::get_if<std::vector<std::string>>(
6778bd25ccdSJames Feist                             &variantEndpoints);
6788bd25ccdSJames Feist 
6798bd25ccdSJames Feist                         if (endpoints == nullptr)
6808bd25ccdSJames Feist                         {
6818bd25ccdSJames Feist                             BMCWEB_LOG_ERROR << "Invalid association interface";
6828bd25ccdSJames Feist                             messages::internalError(sensorsAsyncResp->res);
6838bd25ccdSJames Feist                             return;
6848bd25ccdSJames Feist                         }
6858bd25ccdSJames Feist 
6868bd25ccdSJames Feist                         auto found = std::find_if(
6878bd25ccdSJames Feist                             endpoints->begin(), endpoints->end(),
6888bd25ccdSJames Feist                             [sensorsAsyncResp](const std::string& entry) {
6898bd25ccdSJames Feist                                 return entry.find(
6908bd25ccdSJames Feist                                            sensorsAsyncResp->chassisId) !=
6918bd25ccdSJames Feist                                        std::string::npos;
6928bd25ccdSJames Feist                             });
6938bd25ccdSJames Feist 
6948bd25ccdSJames Feist                         if (found == endpoints->end())
6958bd25ccdSJames Feist                         {
6968bd25ccdSJames Feist                             return;
6978bd25ccdSJames Feist                         }
6988bd25ccdSJames Feist                         crow::connections::systemBus->async_method_call(
6998bd25ccdSJames Feist                             [path, sensorsAsyncResp](
7008bd25ccdSJames Feist                                 const boost::system::error_code ec,
7018bd25ccdSJames Feist                                 const boost::container::flat_map<
7028bd25ccdSJames Feist                                     std::string,
7038bd25ccdSJames Feist                                     std::variant<uint8_t,
7048bd25ccdSJames Feist                                                  std::vector<std::string>,
7058bd25ccdSJames Feist                                                  std::string>>& ret) {
7068bd25ccdSJames Feist                                 if (ec)
7078bd25ccdSJames Feist                                 {
7088bd25ccdSJames Feist                                     return; // don't have to have this
7098bd25ccdSJames Feist                                             // interface
7108bd25ccdSJames Feist                                 }
7118bd25ccdSJames Feist                                 auto findFailures = ret.find("AllowedFailures");
7128bd25ccdSJames Feist                                 auto findCollection = ret.find("Collection");
7138bd25ccdSJames Feist                                 auto findStatus = ret.find("Status");
7148bd25ccdSJames Feist 
7158bd25ccdSJames Feist                                 if (findFailures == ret.end() ||
7168bd25ccdSJames Feist                                     findCollection == ret.end() ||
7178bd25ccdSJames Feist                                     findStatus == ret.end())
7188bd25ccdSJames Feist                                 {
7198bd25ccdSJames Feist                                     BMCWEB_LOG_ERROR
7208bd25ccdSJames Feist                                         << "Invalid redundancy interface";
7218bd25ccdSJames Feist                                     messages::internalError(
7228bd25ccdSJames Feist                                         sensorsAsyncResp->res);
7238bd25ccdSJames Feist                                     return;
7248bd25ccdSJames Feist                                 }
7258bd25ccdSJames Feist 
7268bd25ccdSJames Feist                                 auto allowedFailures = std::get_if<uint8_t>(
7278bd25ccdSJames Feist                                     &(findFailures->second));
7288bd25ccdSJames Feist                                 auto collection =
7298bd25ccdSJames Feist                                     std::get_if<std::vector<std::string>>(
7308bd25ccdSJames Feist                                         &(findCollection->second));
7318bd25ccdSJames Feist                                 auto status = std::get_if<std::string>(
7328bd25ccdSJames Feist                                     &(findStatus->second));
7338bd25ccdSJames Feist 
7348bd25ccdSJames Feist                                 if (allowedFailures == nullptr ||
7358bd25ccdSJames Feist                                     collection == nullptr || status == nullptr)
7368bd25ccdSJames Feist                                 {
7378bd25ccdSJames Feist 
7388bd25ccdSJames Feist                                     BMCWEB_LOG_ERROR
7398bd25ccdSJames Feist                                         << "Invalid redundancy interface "
7408bd25ccdSJames Feist                                            "types";
7418bd25ccdSJames Feist                                     messages::internalError(
7428bd25ccdSJames Feist                                         sensorsAsyncResp->res);
7438bd25ccdSJames Feist                                     return;
7448bd25ccdSJames Feist                                 }
7458bd25ccdSJames Feist                                 size_t lastSlash = path.rfind("/");
7468bd25ccdSJames Feist                                 if (lastSlash == std::string::npos)
7478bd25ccdSJames Feist                                 {
7488bd25ccdSJames Feist                                     // this should be impossible
7498bd25ccdSJames Feist                                     messages::internalError(
7508bd25ccdSJames Feist                                         sensorsAsyncResp->res);
7518bd25ccdSJames Feist                                     return;
7528bd25ccdSJames Feist                                 }
7538bd25ccdSJames Feist                                 std::string name = path.substr(lastSlash + 1);
7548bd25ccdSJames Feist                                 std::replace(name.begin(), name.end(), '_',
7558bd25ccdSJames Feist                                              ' ');
7568bd25ccdSJames Feist 
7578bd25ccdSJames Feist                                 std::string health;
7588bd25ccdSJames Feist 
7598bd25ccdSJames Feist                                 if (boost::ends_with(*status, "Full"))
7608bd25ccdSJames Feist                                 {
7618bd25ccdSJames Feist                                     health = "OK";
7628bd25ccdSJames Feist                                 }
7638bd25ccdSJames Feist                                 else if (boost::ends_with(*status, "Degraded"))
7648bd25ccdSJames Feist                                 {
7658bd25ccdSJames Feist                                     health = "Warning";
7668bd25ccdSJames Feist                                 }
7678bd25ccdSJames Feist                                 else
7688bd25ccdSJames Feist                                 {
7698bd25ccdSJames Feist                                     health = "Critical";
7708bd25ccdSJames Feist                                 }
7718bd25ccdSJames Feist                                 std::vector<nlohmann::json> redfishCollection;
7728bd25ccdSJames Feist                                 const auto& fanRedfish =
7738bd25ccdSJames Feist                                     sensorsAsyncResp->res.jsonValue["Fans"];
7748bd25ccdSJames Feist                                 for (const std::string& item : *collection)
7758bd25ccdSJames Feist                                 {
7768bd25ccdSJames Feist                                     lastSlash = item.rfind("/");
7778bd25ccdSJames Feist                                     // make a copy as collection is const
7788bd25ccdSJames Feist                                     std::string itemName =
7798bd25ccdSJames Feist                                         item.substr(lastSlash + 1);
7808bd25ccdSJames Feist                                     /*
7818bd25ccdSJames Feist                                     todo(ed): merge patch that fixes the names
7828bd25ccdSJames Feist                                     std::replace(itemName.begin(),
7838bd25ccdSJames Feist                                                  itemName.end(), '_', ' ');*/
7848bd25ccdSJames Feist                                     auto schemaItem = std::find_if(
7858bd25ccdSJames Feist                                         fanRedfish.begin(), fanRedfish.end(),
7868bd25ccdSJames Feist                                         [itemName](const nlohmann::json& fan) {
7878bd25ccdSJames Feist                                             return fan["MemberId"] == itemName;
7888bd25ccdSJames Feist                                         });
7898bd25ccdSJames Feist                                     if (schemaItem != fanRedfish.end())
7908bd25ccdSJames Feist                                     {
7918bd25ccdSJames Feist                                         redfishCollection.push_back(
7928bd25ccdSJames Feist                                             {{"@odata.id",
7938bd25ccdSJames Feist                                               (*schemaItem)["@odata.id"]}});
7948bd25ccdSJames Feist                                     }
7958bd25ccdSJames Feist                                     else
7968bd25ccdSJames Feist                                     {
7978bd25ccdSJames Feist                                         BMCWEB_LOG_ERROR
7988bd25ccdSJames Feist                                             << "failed to find fan in schema";
7998bd25ccdSJames Feist                                         messages::internalError(
8008bd25ccdSJames Feist                                             sensorsAsyncResp->res);
8018bd25ccdSJames Feist                                         return;
8028bd25ccdSJames Feist                                     }
8038bd25ccdSJames Feist                                 }
8048bd25ccdSJames Feist 
8058bd25ccdSJames Feist                                 auto& resp = sensorsAsyncResp->res
8068bd25ccdSJames Feist                                                  .jsonValue["Redundancy"];
8078bd25ccdSJames Feist                                 resp.push_back(
8088bd25ccdSJames Feist                                     {{"@odata.id",
8098bd25ccdSJames Feist                                       "/refish/v1/Chassis/" +
8108bd25ccdSJames Feist                                           sensorsAsyncResp->chassisId + "/" +
8118bd25ccdSJames Feist                                           sensorsAsyncResp->chassisSubNode +
8128bd25ccdSJames Feist                                           "#/Redundancy/" +
8138bd25ccdSJames Feist                                           std::to_string(resp.size())},
8148bd25ccdSJames Feist                                      {"@odata.type",
8158bd25ccdSJames Feist                                       "#Redundancy.v1_3_2.Redundancy"},
8168bd25ccdSJames Feist                                      {"MinNumNeeded",
8178bd25ccdSJames Feist                                       collection->size() - *allowedFailures},
8188bd25ccdSJames Feist                                      {"MemberId", name},
8198bd25ccdSJames Feist                                      {"Mode", "N+m"},
8208bd25ccdSJames Feist                                      {"Name", name},
8218bd25ccdSJames Feist                                      {"RedundancySet", redfishCollection},
8228bd25ccdSJames Feist                                      {"Status",
8238bd25ccdSJames Feist                                       {{"Health", health},
8248bd25ccdSJames Feist                                        {"State", "Enabled"}}}});
8258bd25ccdSJames Feist                             },
8268bd25ccdSJames Feist                             owner, path, "org.freedesktop.DBus.Properties",
8278bd25ccdSJames Feist                             "GetAll",
8288bd25ccdSJames Feist                             "xyz.openbmc_project.Control.FanRedundancy");
8298bd25ccdSJames Feist                     },
8308bd25ccdSJames Feist                     "xyz.openbmc_project.ObjectMapper", path + "/inventory",
8318bd25ccdSJames Feist                     "org.freedesktop.DBus.Properties", "Get",
8328bd25ccdSJames Feist                     "xyz.openbmc_project.Association", "endpoints");
8338bd25ccdSJames Feist             }
8348bd25ccdSJames Feist         },
8358bd25ccdSJames Feist         "xyz.openbmc_project.ObjectMapper",
8368bd25ccdSJames Feist         "/xyz/openbmc_project/object_mapper",
8378bd25ccdSJames Feist         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
8388bd25ccdSJames Feist         "/xyz/openbmc_project/control", 2,
8398bd25ccdSJames Feist         std::array<const char*, 1>{
8408bd25ccdSJames Feist             "xyz.openbmc_project.Control.FanRedundancy"});
8418bd25ccdSJames Feist }
8428bd25ccdSJames Feist 
843*49c53ac9SJohnathan Mantey void sortJSONResponse(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
844*49c53ac9SJohnathan Mantey {
845*49c53ac9SJohnathan Mantey     nlohmann::json& response = SensorsAsyncResp->res.jsonValue;
846*49c53ac9SJohnathan Mantey     std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
847*49c53ac9SJohnathan Mantey     if (SensorsAsyncResp->chassisSubNode == "Power")
848*49c53ac9SJohnathan Mantey     {
849*49c53ac9SJohnathan Mantey         sensorHeaders = {"Voltages", "PowerSupplies"};
850*49c53ac9SJohnathan Mantey     }
851*49c53ac9SJohnathan Mantey     for (const std::string& sensorGroup : sensorHeaders)
852*49c53ac9SJohnathan Mantey     {
853*49c53ac9SJohnathan Mantey         nlohmann::json::iterator entry = response.find(sensorGroup);
854*49c53ac9SJohnathan Mantey         if (entry != response.end())
855*49c53ac9SJohnathan Mantey         {
856*49c53ac9SJohnathan Mantey             std::sort(entry->begin(), entry->end(),
857*49c53ac9SJohnathan Mantey                       [](nlohmann::json& c1, nlohmann::json& c2) {
858*49c53ac9SJohnathan Mantey                           return c1["Name"] < c2["Name"];
859*49c53ac9SJohnathan Mantey                       });
860*49c53ac9SJohnathan Mantey 
861*49c53ac9SJohnathan Mantey             // add the index counts to the end of each entry
862*49c53ac9SJohnathan Mantey             size_t count = 0;
863*49c53ac9SJohnathan Mantey             for (nlohmann::json& sensorJson : *entry)
864*49c53ac9SJohnathan Mantey             {
865*49c53ac9SJohnathan Mantey                 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
866*49c53ac9SJohnathan Mantey                 if (odata == sensorJson.end())
867*49c53ac9SJohnathan Mantey                 {
868*49c53ac9SJohnathan Mantey                     continue;
869*49c53ac9SJohnathan Mantey                 }
870*49c53ac9SJohnathan Mantey                 std::string* value = odata->get_ptr<std::string*>();
871*49c53ac9SJohnathan Mantey                 if (value != nullptr)
872*49c53ac9SJohnathan Mantey                 {
873*49c53ac9SJohnathan Mantey                     *value += std::to_string(count);
874*49c53ac9SJohnathan Mantey                     count++;
875*49c53ac9SJohnathan Mantey                 }
876*49c53ac9SJohnathan Mantey             }
877*49c53ac9SJohnathan Mantey         }
878*49c53ac9SJohnathan Mantey     }
879*49c53ac9SJohnathan Mantey }
880*49c53ac9SJohnathan Mantey 
88108777fb0SLewanczyk, Dawid /**
882de629b6eSShawn McCarney  * @brief Gets the values of the specified sensors.
883de629b6eSShawn McCarney  *
884de629b6eSShawn McCarney  * Stores the results as JSON in the SensorsAsyncResp.
885de629b6eSShawn McCarney  *
886de629b6eSShawn McCarney  * Gets the sensor values asynchronously.  Stores the results later when the
887de629b6eSShawn McCarney  * information has been obtained.
888de629b6eSShawn McCarney  *
889de629b6eSShawn McCarney  * The sensorNames set contains all sensors for the current chassis.
890de629b6eSShawn McCarney  * SensorsAsyncResp contains the requested sensor types.  Only sensors of a
891de629b6eSShawn McCarney  * requested type are included in the JSON output.
892de629b6eSShawn McCarney  *
893de629b6eSShawn McCarney  * To minimize the number of DBus calls, the DBus method
894de629b6eSShawn McCarney  * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
895de629b6eSShawn McCarney  * values of all sensors provided by a connection (service).
896de629b6eSShawn McCarney  *
897de629b6eSShawn McCarney  * The connections set contains all the connections that provide sensor values.
898de629b6eSShawn McCarney  *
899de629b6eSShawn McCarney  * The objectMgrPaths map contains mappings from a connection name to the
900de629b6eSShawn McCarney  * corresponding DBus object path that implements ObjectManager.
901de629b6eSShawn McCarney  *
902de629b6eSShawn McCarney  * @param SensorsAsyncResp Pointer to object holding response data.
903de629b6eSShawn McCarney  * @param sensorNames All sensors within the current chassis.
904de629b6eSShawn McCarney  * @param connections Connections that provide sensor values.
905de629b6eSShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
906de629b6eSShawn McCarney  * implements ObjectManager.
907de629b6eSShawn McCarney  */
908de629b6eSShawn McCarney void getSensorData(
909de629b6eSShawn McCarney     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
910*49c53ac9SJohnathan Mantey     const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
911de629b6eSShawn McCarney     const boost::container::flat_set<std::string>& connections,
912de629b6eSShawn McCarney     const boost::container::flat_map<std::string, std::string>& objectMgrPaths)
913de629b6eSShawn McCarney {
914de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getSensorData enter";
915de629b6eSShawn McCarney     // Get managed objects from all services exposing sensors
916de629b6eSShawn McCarney     for (const std::string& connection : connections)
917de629b6eSShawn McCarney     {
918de629b6eSShawn McCarney         // Response handler to process managed objects
919*49c53ac9SJohnathan Mantey         auto getManagedObjectsCb = [SensorsAsyncResp, sensorNames](
920de629b6eSShawn McCarney                                        const boost::system::error_code ec,
921de629b6eSShawn McCarney                                        ManagedObjectsVectorType& resp) {
922de629b6eSShawn McCarney             BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
923de629b6eSShawn McCarney             if (ec)
924de629b6eSShawn McCarney             {
925de629b6eSShawn McCarney                 BMCWEB_LOG_ERROR << "getManagedObjectsCb DBUS error: " << ec;
926de629b6eSShawn McCarney                 messages::internalError(SensorsAsyncResp->res);
927de629b6eSShawn McCarney                 return;
928de629b6eSShawn McCarney             }
929de629b6eSShawn McCarney             // Go through all objects and update response with sensor data
930de629b6eSShawn McCarney             for (const auto& objDictEntry : resp)
931de629b6eSShawn McCarney             {
932de629b6eSShawn McCarney                 const std::string& objPath =
933de629b6eSShawn McCarney                     static_cast<const std::string&>(objDictEntry.first);
934de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "getManagedObjectsCb parsing object "
935de629b6eSShawn McCarney                                  << objPath;
936de629b6eSShawn McCarney 
937de629b6eSShawn McCarney                 std::vector<std::string> split;
938de629b6eSShawn McCarney                 // Reserve space for
939de629b6eSShawn McCarney                 // /xyz/openbmc_project/sensors/<name>/<subname>
940de629b6eSShawn McCarney                 split.reserve(6);
941de629b6eSShawn McCarney                 boost::algorithm::split(split, objPath, boost::is_any_of("/"));
942de629b6eSShawn McCarney                 if (split.size() < 6)
943de629b6eSShawn McCarney                 {
944de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << "Got path that isn't long enough "
945de629b6eSShawn McCarney                                      << objPath;
946de629b6eSShawn McCarney                     continue;
947de629b6eSShawn McCarney                 }
948de629b6eSShawn McCarney                 // These indexes aren't intuitive, as boost::split puts an empty
949de629b6eSShawn McCarney                 // string at the beginning
950de629b6eSShawn McCarney                 const std::string& sensorType = split[4];
951de629b6eSShawn McCarney                 const std::string& sensorName = split[5];
952de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "sensorName " << sensorName
953de629b6eSShawn McCarney                                  << " sensorType " << sensorType;
954*49c53ac9SJohnathan Mantey                 if (sensorNames->find(objPath) == sensorNames->end())
955de629b6eSShawn McCarney                 {
956de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << sensorName << " not in sensor list ";
957de629b6eSShawn McCarney                     continue;
958de629b6eSShawn McCarney                 }
959de629b6eSShawn McCarney 
960de629b6eSShawn McCarney                 const char* fieldName = nullptr;
961de629b6eSShawn McCarney                 if (sensorType == "temperature")
962de629b6eSShawn McCarney                 {
963de629b6eSShawn McCarney                     fieldName = "Temperatures";
964de629b6eSShawn McCarney                 }
965de629b6eSShawn McCarney                 else if (sensorType == "fan" || sensorType == "fan_tach" ||
966de629b6eSShawn McCarney                          sensorType == "fan_pwm")
967de629b6eSShawn McCarney                 {
968de629b6eSShawn McCarney                     fieldName = "Fans";
969de629b6eSShawn McCarney                 }
970de629b6eSShawn McCarney                 else if (sensorType == "voltage")
971de629b6eSShawn McCarney                 {
972de629b6eSShawn McCarney                     fieldName = "Voltages";
973de629b6eSShawn McCarney                 }
974de629b6eSShawn McCarney                 else if (sensorType == "current")
975de629b6eSShawn McCarney                 {
976de629b6eSShawn McCarney                     fieldName = "PowerSupplies";
977de629b6eSShawn McCarney                 }
978de629b6eSShawn McCarney                 else if (sensorType == "power")
979de629b6eSShawn McCarney                 {
980de629b6eSShawn McCarney                     fieldName = "PowerSupplies";
981de629b6eSShawn McCarney                 }
982de629b6eSShawn McCarney                 else
983de629b6eSShawn McCarney                 {
984de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << "Unsure how to handle sensorType "
985de629b6eSShawn McCarney                                      << sensorType;
986de629b6eSShawn McCarney                     continue;
987de629b6eSShawn McCarney                 }
988de629b6eSShawn McCarney 
989de629b6eSShawn McCarney                 nlohmann::json& tempArray =
990de629b6eSShawn McCarney                     SensorsAsyncResp->res.jsonValue[fieldName];
991de629b6eSShawn McCarney 
992*49c53ac9SJohnathan Mantey                 if (fieldName == "PowerSupplies" && !tempArray.empty())
993*49c53ac9SJohnathan Mantey                 {
994*49c53ac9SJohnathan Mantey                     // Power supplies put multiple "sensors" into a single power
995*49c53ac9SJohnathan Mantey                     // supply entry, so only create the first one
996*49c53ac9SJohnathan Mantey                 }
997*49c53ac9SJohnathan Mantey                 else
998*49c53ac9SJohnathan Mantey                 {
999de629b6eSShawn McCarney                     tempArray.push_back(
1000*49c53ac9SJohnathan Mantey                         {{"@odata.id", "/redfish/v1/Chassis/" +
1001*49c53ac9SJohnathan Mantey                                            SensorsAsyncResp->chassisId + "/" +
1002*49c53ac9SJohnathan Mantey                                            SensorsAsyncResp->chassisSubNode +
1003*49c53ac9SJohnathan Mantey                                            "#/" + fieldName + "/"}});
1004*49c53ac9SJohnathan Mantey                 }
1005de629b6eSShawn McCarney                 nlohmann::json& sensorJson = tempArray.back();
1006de629b6eSShawn McCarney 
1007de629b6eSShawn McCarney                 objectInterfacesToJson(sensorName, sensorType,
1008de629b6eSShawn McCarney                                        objDictEntry.second, sensorJson);
1009de629b6eSShawn McCarney             }
1010*49c53ac9SJohnathan Mantey             if (SensorsAsyncResp.use_count() == 1)
1011*49c53ac9SJohnathan Mantey             {
1012*49c53ac9SJohnathan Mantey                 sortJSONResponse(SensorsAsyncResp);
1013*49c53ac9SJohnathan Mantey                 if (SensorsAsyncResp->chassisSubNode == "Thermal")
10148bd25ccdSJames Feist                 {
10158bd25ccdSJames Feist                     populateFanRedundancy(SensorsAsyncResp);
10168bd25ccdSJames Feist                 }
1017*49c53ac9SJohnathan Mantey             }
1018de629b6eSShawn McCarney             BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
1019de629b6eSShawn McCarney         };
1020de629b6eSShawn McCarney 
1021de629b6eSShawn McCarney         // Find DBus object path that implements ObjectManager for the current
1022de629b6eSShawn McCarney         // connection.  If no mapping found, default to "/".
1023de629b6eSShawn McCarney         auto iter = objectMgrPaths.find(connection);
1024de629b6eSShawn McCarney         const std::string& objectMgrPath =
1025de629b6eSShawn McCarney             (iter != objectMgrPaths.end()) ? iter->second : "/";
1026de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
1027de629b6eSShawn McCarney                          << objectMgrPath;
1028de629b6eSShawn McCarney 
1029de629b6eSShawn McCarney         crow::connections::systemBus->async_method_call(
1030de629b6eSShawn McCarney             getManagedObjectsCb, connection, objectMgrPath,
1031de629b6eSShawn McCarney             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1032de629b6eSShawn McCarney     };
1033de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getSensorData exit";
1034de629b6eSShawn McCarney }
1035de629b6eSShawn McCarney 
1036de629b6eSShawn McCarney /**
103708777fb0SLewanczyk, Dawid  * @brief Entry point for retrieving sensors data related to requested
103808777fb0SLewanczyk, Dawid  *        chassis.
1039588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
104008777fb0SLewanczyk, Dawid  */
10411abe55efSEd Tanous void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
10421abe55efSEd Tanous {
104355c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisData enter";
1044*49c53ac9SJohnathan Mantey     auto getChassisCb =
1045*49c53ac9SJohnathan Mantey         [SensorsAsyncResp](
1046*49c53ac9SJohnathan Mantey             std::shared_ptr<boost::container::flat_set<std::string>>
104708777fb0SLewanczyk, Dawid                 sensorNames) {
104855c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "getChassisCb enter";
1049588c3f0dSKowalski, Kamil             auto getConnectionCb =
1050*49c53ac9SJohnathan Mantey                 [SensorsAsyncResp,
1051*49c53ac9SJohnathan Mantey                  sensorNames](const boost::container::flat_set<std::string>&
1052*49c53ac9SJohnathan Mantey                                   connections) {
105355c7b7a2SEd Tanous                     BMCWEB_LOG_DEBUG << "getConnectionCb enter";
1054de629b6eSShawn McCarney                     auto getObjectManagerPathsCb =
1055*49c53ac9SJohnathan Mantey                         [SensorsAsyncResp, sensorNames, connections](
1056*49c53ac9SJohnathan Mantey                             const boost::container::flat_map<
1057de629b6eSShawn McCarney                                 std::string, std::string>& objectMgrPaths) {
1058de629b6eSShawn McCarney                             BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb enter";
1059*49c53ac9SJohnathan Mantey                             // Get sensor data and store results in JSON
1060*49c53ac9SJohnathan Mantey                             // response
1061de629b6eSShawn McCarney                             getSensorData(SensorsAsyncResp, sensorNames,
1062de629b6eSShawn McCarney                                           connections, objectMgrPaths);
1063de629b6eSShawn McCarney                             BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb exit";
106408777fb0SLewanczyk, Dawid                         };
1065de629b6eSShawn McCarney 
1066*49c53ac9SJohnathan Mantey                     // Get mapping from connection names to the DBus object
1067*49c53ac9SJohnathan Mantey                     // paths that implement the ObjectManager interface
1068de629b6eSShawn McCarney                     getObjectManagerPaths(SensorsAsyncResp,
1069de629b6eSShawn McCarney                                           std::move(getObjectManagerPathsCb));
107055c7b7a2SEd Tanous                     BMCWEB_LOG_DEBUG << "getConnectionCb exit";
107108777fb0SLewanczyk, Dawid                 };
1072de629b6eSShawn McCarney 
1073de629b6eSShawn McCarney             // Get set of connections that provide sensor values
10741abe55efSEd Tanous             getConnections(SensorsAsyncResp, sensorNames,
10751abe55efSEd Tanous                            std::move(getConnectionCb));
107655c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "getChassisCb exit";
107708777fb0SLewanczyk, Dawid         };
107808777fb0SLewanczyk, Dawid 
1079de629b6eSShawn McCarney #ifdef BMCWEB_ENABLE_REDFISH_ONE_CHASSIS
1080de629b6eSShawn McCarney     // Get all sensor names
1081de629b6eSShawn McCarney     getAllSensors(SensorsAsyncResp, std::move(getChassisCb));
1082de629b6eSShawn McCarney #else
1083de629b6eSShawn McCarney     // Get sensor names in chassis
1084588c3f0dSKowalski, Kamil     getChassis(SensorsAsyncResp, std::move(getChassisCb));
1085de629b6eSShawn McCarney #endif
108655c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisData exit";
108708777fb0SLewanczyk, Dawid };
108808777fb0SLewanczyk, Dawid 
1089413961deSRichard Marian Thomaiyar /**
1090*49c53ac9SJohnathan Mantey  * @brief Find the requested sensorName in the list of all sensors supplied by
1091*49c53ac9SJohnathan Mantey  * the chassis node
1092*49c53ac9SJohnathan Mantey  *
1093*49c53ac9SJohnathan Mantey  * @param sensorName   The sensor name supplied in the PATCH request
1094*49c53ac9SJohnathan Mantey  * @param sensorsList  The list of sensors managed by the chassis node
1095*49c53ac9SJohnathan Mantey  * @param sensorsModified  The list of sensors that were found as a result of
1096*49c53ac9SJohnathan Mantey  *                         repeated calls to this function
1097*49c53ac9SJohnathan Mantey  */
1098*49c53ac9SJohnathan Mantey bool findSensorNameUsingSensorPath(
1099*49c53ac9SJohnathan Mantey     const std::string& sensorName,
1100*49c53ac9SJohnathan Mantey     boost::container::flat_set<std::string>& sensorsList,
1101*49c53ac9SJohnathan Mantey     boost::container::flat_set<std::string>& sensorsModified)
1102*49c53ac9SJohnathan Mantey {
1103*49c53ac9SJohnathan Mantey     for (const std::string& chassisSensor : sensorsList)
1104*49c53ac9SJohnathan Mantey     {
1105*49c53ac9SJohnathan Mantey         std::string thisSensorName;
1106*49c53ac9SJohnathan Mantey         if (!dbus::utility::getNthStringFromPath(chassisSensor, 5,
1107*49c53ac9SJohnathan Mantey                                                  thisSensorName))
1108*49c53ac9SJohnathan Mantey         {
1109*49c53ac9SJohnathan Mantey             BMCWEB_LOG_ERROR << "Got path that isn't long enough "
1110*49c53ac9SJohnathan Mantey                              << chassisSensor;
1111*49c53ac9SJohnathan Mantey             continue;
1112*49c53ac9SJohnathan Mantey         }
1113*49c53ac9SJohnathan Mantey         if (thisSensorName == sensorName)
1114*49c53ac9SJohnathan Mantey         {
1115*49c53ac9SJohnathan Mantey             sensorsModified.emplace(chassisSensor);
1116*49c53ac9SJohnathan Mantey             return true;
1117*49c53ac9SJohnathan Mantey         }
1118*49c53ac9SJohnathan Mantey     }
1119*49c53ac9SJohnathan Mantey     return false;
1120*49c53ac9SJohnathan Mantey }
1121*49c53ac9SJohnathan Mantey 
1122*49c53ac9SJohnathan Mantey /**
1123413961deSRichard Marian Thomaiyar  * @brief Entry point for overriding sensor values of given sensor
1124413961deSRichard Marian Thomaiyar  *
1125413961deSRichard Marian Thomaiyar  * @param res   response object
1126413961deSRichard Marian Thomaiyar  * @param req   request object
1127413961deSRichard Marian Thomaiyar  * @param params   parameter passed for CRUD
1128413961deSRichard Marian Thomaiyar  * @param typeList   TypeList of sensors for the resource queried
1129413961deSRichard Marian Thomaiyar  * @param chassisSubNode   Chassis Node for which the query has to happen
1130413961deSRichard Marian Thomaiyar  */
1131413961deSRichard Marian Thomaiyar void setSensorOverride(crow::Response& res, const crow::Request& req,
1132413961deSRichard Marian Thomaiyar                        const std::vector<std::string>& params,
1133b01bf299SEd Tanous                        const std::initializer_list<const char*> typeList,
1134413961deSRichard Marian Thomaiyar                        const std::string& chassisSubNode)
1135413961deSRichard Marian Thomaiyar {
1136413961deSRichard Marian Thomaiyar 
1137413961deSRichard Marian Thomaiyar     // TODO: Need to figure out dynamic way to restrict patch (Set Sensor
1138413961deSRichard Marian Thomaiyar     // override) based on another d-bus announcement to be more generic.
1139413961deSRichard Marian Thomaiyar     if (params.size() != 1)
1140413961deSRichard Marian Thomaiyar     {
1141413961deSRichard Marian Thomaiyar         messages::internalError(res);
1142413961deSRichard Marian Thomaiyar         res.end();
1143413961deSRichard Marian Thomaiyar         return;
1144413961deSRichard Marian Thomaiyar     }
1145f65af9e8SRichard Marian Thomaiyar 
1146f65af9e8SRichard Marian Thomaiyar     std::unordered_map<std::string, std::vector<nlohmann::json>> allCollections;
1147f65af9e8SRichard Marian Thomaiyar     std::optional<std::vector<nlohmann::json>> temperatureCollections;
1148f65af9e8SRichard Marian Thomaiyar     std::optional<std::vector<nlohmann::json>> fanCollections;
1149f65af9e8SRichard Marian Thomaiyar     std::vector<nlohmann::json> voltageCollections;
1150f65af9e8SRichard Marian Thomaiyar     BMCWEB_LOG_INFO << "setSensorOverride for subNode" << chassisSubNode
1151f65af9e8SRichard Marian Thomaiyar                     << "\n";
1152f65af9e8SRichard Marian Thomaiyar 
1153413961deSRichard Marian Thomaiyar     if (chassisSubNode == "Thermal")
1154413961deSRichard Marian Thomaiyar     {
1155f65af9e8SRichard Marian Thomaiyar         if (!json_util::readJson(req, res, "Temperatures",
1156f65af9e8SRichard Marian Thomaiyar                                  temperatureCollections, "Fans",
1157f65af9e8SRichard Marian Thomaiyar                                  fanCollections))
1158f65af9e8SRichard Marian Thomaiyar         {
1159f65af9e8SRichard Marian Thomaiyar             return;
1160f65af9e8SRichard Marian Thomaiyar         }
1161f65af9e8SRichard Marian Thomaiyar         if (!temperatureCollections && !fanCollections)
1162f65af9e8SRichard Marian Thomaiyar         {
1163f65af9e8SRichard Marian Thomaiyar             messages::resourceNotFound(res, "Thermal",
1164f65af9e8SRichard Marian Thomaiyar                                        "Temperatures / Voltages");
1165f65af9e8SRichard Marian Thomaiyar             res.end();
1166f65af9e8SRichard Marian Thomaiyar             return;
1167f65af9e8SRichard Marian Thomaiyar         }
1168f65af9e8SRichard Marian Thomaiyar         if (temperatureCollections)
1169f65af9e8SRichard Marian Thomaiyar         {
1170f65af9e8SRichard Marian Thomaiyar             allCollections.emplace("Temperatures",
1171f65af9e8SRichard Marian Thomaiyar                                    *std::move(temperatureCollections));
1172f65af9e8SRichard Marian Thomaiyar         }
1173f65af9e8SRichard Marian Thomaiyar         if (fanCollections)
1174f65af9e8SRichard Marian Thomaiyar         {
1175f65af9e8SRichard Marian Thomaiyar             allCollections.emplace("Fans", *std::move(fanCollections));
1176f65af9e8SRichard Marian Thomaiyar         }
1177413961deSRichard Marian Thomaiyar     }
1178413961deSRichard Marian Thomaiyar     else if (chassisSubNode == "Power")
1179413961deSRichard Marian Thomaiyar     {
1180f65af9e8SRichard Marian Thomaiyar         if (!json_util::readJson(req, res, "Voltages", voltageCollections))
1181f65af9e8SRichard Marian Thomaiyar         {
1182f65af9e8SRichard Marian Thomaiyar             return;
1183f65af9e8SRichard Marian Thomaiyar         }
1184f65af9e8SRichard Marian Thomaiyar         allCollections.emplace("Voltages", std::move(voltageCollections));
1185413961deSRichard Marian Thomaiyar     }
1186413961deSRichard Marian Thomaiyar     else
1187413961deSRichard Marian Thomaiyar     {
1188413961deSRichard Marian Thomaiyar         res.result(boost::beast::http::status::not_found);
1189413961deSRichard Marian Thomaiyar         res.end();
1190413961deSRichard Marian Thomaiyar         return;
1191413961deSRichard Marian Thomaiyar     }
1192413961deSRichard Marian Thomaiyar 
1193f65af9e8SRichard Marian Thomaiyar     const char* propertyValueName;
1194f65af9e8SRichard Marian Thomaiyar     std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
1195413961deSRichard Marian Thomaiyar     std::string memberId;
1196413961deSRichard Marian Thomaiyar     double value;
1197f65af9e8SRichard Marian Thomaiyar     for (auto& collectionItems : allCollections)
1198f65af9e8SRichard Marian Thomaiyar     {
1199f65af9e8SRichard Marian Thomaiyar         if (collectionItems.first == "Temperatures")
1200f65af9e8SRichard Marian Thomaiyar         {
1201f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingCelsius";
1202f65af9e8SRichard Marian Thomaiyar         }
1203f65af9e8SRichard Marian Thomaiyar         else if (collectionItems.first == "Fans")
1204f65af9e8SRichard Marian Thomaiyar         {
1205f65af9e8SRichard Marian Thomaiyar             propertyValueName = "Reading";
1206f65af9e8SRichard Marian Thomaiyar         }
1207f65af9e8SRichard Marian Thomaiyar         else
1208f65af9e8SRichard Marian Thomaiyar         {
1209f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingVolts";
1210f65af9e8SRichard Marian Thomaiyar         }
1211f65af9e8SRichard Marian Thomaiyar         for (auto& item : collectionItems.second)
1212f65af9e8SRichard Marian Thomaiyar         {
1213f65af9e8SRichard Marian Thomaiyar             if (!json_util::readJson(item, res, "MemberId", memberId,
1214413961deSRichard Marian Thomaiyar                                      propertyValueName, value))
1215413961deSRichard Marian Thomaiyar             {
1216413961deSRichard Marian Thomaiyar                 return;
1217413961deSRichard Marian Thomaiyar             }
1218f65af9e8SRichard Marian Thomaiyar             overrideMap.emplace(memberId,
1219f65af9e8SRichard Marian Thomaiyar                                 std::make_pair(value, collectionItems.first));
1220f65af9e8SRichard Marian Thomaiyar         }
1221f65af9e8SRichard Marian Thomaiyar     }
1222413961deSRichard Marian Thomaiyar     const std::string& chassisName = params[0];
1223413961deSRichard Marian Thomaiyar     auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
1224413961deSRichard Marian Thomaiyar         res, chassisName, typeList, chassisSubNode);
1225*49c53ac9SJohnathan Mantey     auto getChassisSensorListCb = [sensorAsyncResp,
1226*49c53ac9SJohnathan Mantey                                    overrideMap](const std::shared_ptr<
1227*49c53ac9SJohnathan Mantey                                                 boost::container::flat_set<
1228*49c53ac9SJohnathan Mantey                                                     std::string>>
1229*49c53ac9SJohnathan Mantey                                                     sensorsList) {
1230*49c53ac9SJohnathan Mantey         // Match sensor names in the PATCH request to those managed by the
1231*49c53ac9SJohnathan Mantey         // chassis node
1232*49c53ac9SJohnathan Mantey         const std::shared_ptr<boost::container::flat_set<std::string>>
1233*49c53ac9SJohnathan Mantey             sensorNames =
1234*49c53ac9SJohnathan Mantey                 std::make_shared<boost::container::flat_set<std::string>>();
1235f65af9e8SRichard Marian Thomaiyar         for (const auto& item : overrideMap)
1236413961deSRichard Marian Thomaiyar         {
1237f65af9e8SRichard Marian Thomaiyar             const auto& sensor = item.first;
1238*49c53ac9SJohnathan Mantey             if (!findSensorNameUsingSensorPath(sensor, *sensorsList,
1239*49c53ac9SJohnathan Mantey                                                *sensorNames))
1240f65af9e8SRichard Marian Thomaiyar             {
1241f65af9e8SRichard Marian Thomaiyar                 BMCWEB_LOG_INFO << "Unable to find memberId " << item.first;
1242413961deSRichard Marian Thomaiyar                 messages::resourceNotFound(sensorAsyncResp->res,
1243f65af9e8SRichard Marian Thomaiyar                                            item.second.second, item.first);
1244413961deSRichard Marian Thomaiyar                 return;
1245413961deSRichard Marian Thomaiyar             }
1246f65af9e8SRichard Marian Thomaiyar         }
1247413961deSRichard Marian Thomaiyar         // Get the connection to which the memberId belongs
1248413961deSRichard Marian Thomaiyar         auto getObjectsWithConnectionCb =
1249f65af9e8SRichard Marian Thomaiyar             [sensorAsyncResp, overrideMap](
1250413961deSRichard Marian Thomaiyar                 const boost::container::flat_set<std::string>& connections,
1251413961deSRichard Marian Thomaiyar                 const std::set<std::pair<std::string, std::string>>&
1252413961deSRichard Marian Thomaiyar                     objectsWithConnection) {
1253f65af9e8SRichard Marian Thomaiyar                 if (objectsWithConnection.size() != overrideMap.size())
1254413961deSRichard Marian Thomaiyar                 {
1255413961deSRichard Marian Thomaiyar                     BMCWEB_LOG_INFO
1256f65af9e8SRichard Marian Thomaiyar                         << "Unable to find all objects with proper connection "
1257f65af9e8SRichard Marian Thomaiyar                         << objectsWithConnection.size() << " requested "
1258f65af9e8SRichard Marian Thomaiyar                         << overrideMap.size() << "\n";
1259413961deSRichard Marian Thomaiyar                     messages::resourceNotFound(
1260413961deSRichard Marian Thomaiyar                         sensorAsyncResp->res,
1261413961deSRichard Marian Thomaiyar                         sensorAsyncResp->chassisSubNode == "Thermal"
1262413961deSRichard Marian Thomaiyar                             ? "Temperatures"
1263413961deSRichard Marian Thomaiyar                             : "Voltages",
1264f65af9e8SRichard Marian Thomaiyar                         "Count");
1265f65af9e8SRichard Marian Thomaiyar                     return;
1266f65af9e8SRichard Marian Thomaiyar                 }
1267f65af9e8SRichard Marian Thomaiyar                 for (const auto& item : objectsWithConnection)
1268f65af9e8SRichard Marian Thomaiyar                 {
1269f65af9e8SRichard Marian Thomaiyar 
1270f65af9e8SRichard Marian Thomaiyar                     auto lastPos = item.first.rfind('/');
1271f65af9e8SRichard Marian Thomaiyar                     if (lastPos == std::string::npos)
1272f65af9e8SRichard Marian Thomaiyar                     {
1273f65af9e8SRichard Marian Thomaiyar                         messages::internalError(sensorAsyncResp->res);
1274f65af9e8SRichard Marian Thomaiyar                         return;
1275f65af9e8SRichard Marian Thomaiyar                     }
1276f65af9e8SRichard Marian Thomaiyar                     std::string sensorName = item.first.substr(lastPos + 1);
1277f65af9e8SRichard Marian Thomaiyar 
1278f65af9e8SRichard Marian Thomaiyar                     const auto& iterator = overrideMap.find(sensorName);
1279f65af9e8SRichard Marian Thomaiyar                     if (iterator == overrideMap.end())
1280f65af9e8SRichard Marian Thomaiyar                     {
1281f65af9e8SRichard Marian Thomaiyar                         BMCWEB_LOG_INFO << "Unable to find sensor object"
1282f65af9e8SRichard Marian Thomaiyar                                         << item.first << "\n";
1283f65af9e8SRichard Marian Thomaiyar                         messages::internalError(sensorAsyncResp->res);
1284413961deSRichard Marian Thomaiyar                         return;
1285413961deSRichard Marian Thomaiyar                     }
1286413961deSRichard Marian Thomaiyar                     crow::connections::systemBus->async_method_call(
1287f65af9e8SRichard Marian Thomaiyar                         [sensorAsyncResp](const boost::system::error_code ec) {
1288413961deSRichard Marian Thomaiyar                             if (ec)
1289413961deSRichard Marian Thomaiyar                             {
1290413961deSRichard Marian Thomaiyar                                 BMCWEB_LOG_DEBUG
1291f65af9e8SRichard Marian Thomaiyar                                     << "setOverrideValueStatus DBUS error: "
1292413961deSRichard Marian Thomaiyar                                     << ec;
1293413961deSRichard Marian Thomaiyar                                 messages::internalError(sensorAsyncResp->res);
1294413961deSRichard Marian Thomaiyar                                 return;
1295413961deSRichard Marian Thomaiyar                             }
1296413961deSRichard Marian Thomaiyar                         },
1297f65af9e8SRichard Marian Thomaiyar                         item.second, item.first,
1298413961deSRichard Marian Thomaiyar                         "org.freedesktop.DBus.Properties", "Set",
1299413961deSRichard Marian Thomaiyar                         "xyz.openbmc_project.Sensor.Value", "Value",
1300f65af9e8SRichard Marian Thomaiyar                         sdbusplus::message::variant<double>(
1301f65af9e8SRichard Marian Thomaiyar                             iterator->second.first));
1302f65af9e8SRichard Marian Thomaiyar                 }
1303413961deSRichard Marian Thomaiyar             };
1304413961deSRichard Marian Thomaiyar         // Get object with connection for the given sensor name
1305413961deSRichard Marian Thomaiyar         getObjectsWithConnection(sensorAsyncResp, sensorNames,
1306413961deSRichard Marian Thomaiyar                                  std::move(getObjectsWithConnectionCb));
1307413961deSRichard Marian Thomaiyar     };
1308413961deSRichard Marian Thomaiyar     // get full sensor list for the given chassisId and cross verify the sensor.
1309413961deSRichard Marian Thomaiyar     getChassis(sensorAsyncResp, std::move(getChassisSensorListCb));
1310413961deSRichard Marian Thomaiyar }
1311413961deSRichard Marian Thomaiyar 
131208777fb0SLewanczyk, Dawid } // namespace redfish
1313