xref: /openbmc/bmcweb/features/redfish/lib/sensors.hpp (revision e278c18fc22faa2e5099f3f43a813942144c7560)
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     {
5755c7b7a2SEd Tanous         res.jsonValue["@odata.id"] =
58413961deSRichard Marian Thomaiyar             "/redfish/v1/Chassis/" + chassisId + "/" + subNode;
5908777fb0SLewanczyk, Dawid     }
6008777fb0SLewanczyk, Dawid 
611abe55efSEd Tanous     ~SensorsAsyncResp()
621abe55efSEd Tanous     {
631abe55efSEd Tanous         if (res.result() == boost::beast::http::status::internal_server_error)
641abe55efSEd Tanous         {
651abe55efSEd Tanous             // Reset the json object to clear out any data that made it in
661abe55efSEd Tanous             // before the error happened todo(ed) handle error condition with
671abe55efSEd Tanous             // proper code
6855c7b7a2SEd Tanous             res.jsonValue = nlohmann::json::object();
6908777fb0SLewanczyk, Dawid         }
7008777fb0SLewanczyk, Dawid         res.end();
7108777fb0SLewanczyk, Dawid     }
72588c3f0dSKowalski, Kamil 
7355c7b7a2SEd Tanous     crow::Response& res;
74588c3f0dSKowalski, Kamil     std::string chassisId{};
7508777fb0SLewanczyk, Dawid     const std::vector<const char*> types;
762474adfaSEd Tanous     std::string chassisSubNode{};
7708777fb0SLewanczyk, Dawid };
7808777fb0SLewanczyk, Dawid 
7908777fb0SLewanczyk, Dawid /**
80de629b6eSShawn McCarney  * @brief Checks whether the specified sensor is one of the requested types.
81de629b6eSShawn McCarney  * @param objectPath DBus object path of the sensor.
82de629b6eSShawn McCarney  * @param SensorsAsyncResp Pointer to object holding response data and requested
83de629b6eSShawn McCarney  * sensor types.
84de629b6eSShawn McCarney  * @return true if sensor type is requested, false otherwise.
85de629b6eSShawn McCarney  */
86de629b6eSShawn McCarney inline bool
87de629b6eSShawn McCarney     isRequestedSensorType(const std::string& objectPath,
88de629b6eSShawn McCarney                           std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
89de629b6eSShawn McCarney {
90de629b6eSShawn McCarney     for (const char* type : SensorsAsyncResp->types)
91de629b6eSShawn McCarney     {
92de629b6eSShawn McCarney         if (boost::starts_with(objectPath, type))
93de629b6eSShawn McCarney         {
94de629b6eSShawn McCarney             return true;
95de629b6eSShawn McCarney         }
96de629b6eSShawn McCarney     }
97de629b6eSShawn McCarney     return false;
98de629b6eSShawn McCarney }
99de629b6eSShawn McCarney 
100de629b6eSShawn McCarney /**
101413961deSRichard Marian Thomaiyar  * @brief Get objects with connection necessary for sensors
102588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp Pointer to object holding response data
10308777fb0SLewanczyk, Dawid  * @param sensorNames Sensors retrieved from chassis
10408777fb0SLewanczyk, Dawid  * @param callback Callback for processing gathered connections
10508777fb0SLewanczyk, Dawid  */
10608777fb0SLewanczyk, Dawid template <typename Callback>
107413961deSRichard Marian Thomaiyar void getObjectsWithConnection(
108413961deSRichard Marian Thomaiyar     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
10908777fb0SLewanczyk, Dawid     const boost::container::flat_set<std::string>& sensorNames,
1101abe55efSEd Tanous     Callback&& callback)
1111abe55efSEd Tanous {
112413961deSRichard Marian Thomaiyar     BMCWEB_LOG_DEBUG << "getObjectsWithConnection enter";
11303b5bae3SJames Feist     const std::string path = "/xyz/openbmc_project/sensors";
11408777fb0SLewanczyk, Dawid     const std::array<std::string, 1> interfaces = {
11508777fb0SLewanczyk, Dawid         "xyz.openbmc_project.Sensor.Value"};
11608777fb0SLewanczyk, Dawid 
11708777fb0SLewanczyk, Dawid     // Response handler for parsing objects subtree
1181abe55efSEd Tanous     auto respHandler = [callback{std::move(callback)}, SensorsAsyncResp,
1191abe55efSEd Tanous                         sensorNames](const boost::system::error_code ec,
1201abe55efSEd Tanous                                      const GetSubTreeType& subtree) {
121413961deSRichard Marian Thomaiyar         BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler enter";
1221abe55efSEd Tanous         if (ec)
1231abe55efSEd Tanous         {
1245f7d88c4SEd Tanous             messages::internalError(SensorsAsyncResp->res);
125413961deSRichard Marian Thomaiyar             BMCWEB_LOG_ERROR
126413961deSRichard Marian Thomaiyar                 << "getObjectsWithConnection resp_handler: Dbus error " << ec;
12708777fb0SLewanczyk, Dawid             return;
12808777fb0SLewanczyk, Dawid         }
12908777fb0SLewanczyk, Dawid 
13055c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
13108777fb0SLewanczyk, Dawid 
13208777fb0SLewanczyk, Dawid         // Make unique list of connections only for requested sensor types and
13308777fb0SLewanczyk, Dawid         // found in the chassis
13408777fb0SLewanczyk, Dawid         boost::container::flat_set<std::string> connections;
135413961deSRichard Marian Thomaiyar         std::set<std::pair<std::string, std::string>> objectsWithConnection;
1361abe55efSEd Tanous         // Intrinsic to avoid malloc.  Most systems will have < 8 sensor
1371abe55efSEd Tanous         // producers
13808777fb0SLewanczyk, Dawid         connections.reserve(8);
13908777fb0SLewanczyk, Dawid 
14055c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames.size();
1411abe55efSEd Tanous         for (const std::string& tsensor : sensorNames)
1421abe55efSEd Tanous         {
14355c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor;
14408777fb0SLewanczyk, Dawid         }
14508777fb0SLewanczyk, Dawid 
14608777fb0SLewanczyk, Dawid         for (const std::pair<
14708777fb0SLewanczyk, Dawid                  std::string,
14808777fb0SLewanczyk, Dawid                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
1491abe55efSEd Tanous                  object : subtree)
1501abe55efSEd Tanous         {
151de629b6eSShawn McCarney             if (isRequestedSensorType(object.first, SensorsAsyncResp))
1521abe55efSEd Tanous             {
15308777fb0SLewanczyk, Dawid                 auto lastPos = object.first.rfind('/');
1541abe55efSEd Tanous                 if (lastPos != std::string::npos)
1551abe55efSEd Tanous                 {
156de629b6eSShawn McCarney                     std::string sensorName = object.first.substr(lastPos + 1);
15708777fb0SLewanczyk, Dawid 
1581abe55efSEd Tanous                     if (sensorNames.find(sensorName) != sensorNames.end())
1591abe55efSEd Tanous                     {
16055c7b7a2SEd Tanous                         // For each Connection name
1611abe55efSEd Tanous                         for (const std::pair<std::string,
1621abe55efSEd Tanous                                              std::vector<std::string>>&
1631abe55efSEd Tanous                                  objData : object.second)
1641abe55efSEd Tanous                         {
1651abe55efSEd Tanous                             BMCWEB_LOG_DEBUG << "Adding connection: "
1661abe55efSEd Tanous                                              << objData.first;
16708777fb0SLewanczyk, Dawid                             connections.insert(objData.first);
168de629b6eSShawn McCarney                             objectsWithConnection.insert(
169de629b6eSShawn McCarney                                 std::make_pair(object.first, objData.first));
17008777fb0SLewanczyk, Dawid                         }
17108777fb0SLewanczyk, Dawid                     }
17208777fb0SLewanczyk, Dawid                 }
17308777fb0SLewanczyk, Dawid             }
17408777fb0SLewanczyk, Dawid         }
17555c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections";
176413961deSRichard Marian Thomaiyar         callback(std::move(connections), std::move(objectsWithConnection));
177413961deSRichard Marian Thomaiyar         BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler exit";
17808777fb0SLewanczyk, Dawid     };
17908777fb0SLewanczyk, Dawid     // Make call to ObjectMapper to find all sensors objects
18055c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
18155c7b7a2SEd Tanous         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
1821abe55efSEd Tanous         "/xyz/openbmc_project/object_mapper",
1831abe55efSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 2, interfaces);
184413961deSRichard Marian Thomaiyar     BMCWEB_LOG_DEBUG << "getObjectsWithConnection exit";
185413961deSRichard Marian Thomaiyar }
186413961deSRichard Marian Thomaiyar 
187413961deSRichard Marian Thomaiyar /**
188413961deSRichard Marian Thomaiyar  * @brief Create connections necessary for sensors
189413961deSRichard Marian Thomaiyar  * @param SensorsAsyncResp Pointer to object holding response data
190413961deSRichard Marian Thomaiyar  * @param sensorNames Sensors retrieved from chassis
191413961deSRichard Marian Thomaiyar  * @param callback Callback for processing gathered connections
192413961deSRichard Marian Thomaiyar  */
193413961deSRichard Marian Thomaiyar template <typename Callback>
194413961deSRichard Marian Thomaiyar void getConnections(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
195413961deSRichard Marian Thomaiyar                     const boost::container::flat_set<std::string>& sensorNames,
196413961deSRichard Marian Thomaiyar                     Callback&& callback)
197413961deSRichard Marian Thomaiyar {
198413961deSRichard Marian Thomaiyar     auto objectsWithConnectionCb =
199413961deSRichard Marian Thomaiyar         [callback](const boost::container::flat_set<std::string>& connections,
200413961deSRichard Marian Thomaiyar                    const std::set<std::pair<std::string, std::string>>&
201413961deSRichard Marian Thomaiyar                        objectsWithConnection) {
202413961deSRichard Marian Thomaiyar             callback(std::move(connections));
203413961deSRichard Marian Thomaiyar         };
204413961deSRichard Marian Thomaiyar     getObjectsWithConnection(SensorsAsyncResp, sensorNames,
205413961deSRichard Marian Thomaiyar                              std::move(objectsWithConnectionCb));
20608777fb0SLewanczyk, Dawid }
20708777fb0SLewanczyk, Dawid 
20808777fb0SLewanczyk, Dawid /**
209de629b6eSShawn McCarney  * @brief Gets all DBus sensor names.
210de629b6eSShawn McCarney  *
211de629b6eSShawn McCarney  * Finds the sensor names asynchronously.  Invokes callback when information has
212de629b6eSShawn McCarney  * been obtained.
213de629b6eSShawn McCarney  *
214de629b6eSShawn McCarney  * The callback must have the following signature:
215de629b6eSShawn McCarney  *   @code
216de629b6eSShawn McCarney  *   callback(boost::container::flat_set<std::string>& sensorNames)
217de629b6eSShawn McCarney  *   @endcode
218de629b6eSShawn McCarney  *
219de629b6eSShawn McCarney  * @param SensorsAsyncResp Pointer to object holding response data.
220de629b6eSShawn McCarney  * @param callback Callback to invoke when sensor names obtained.
221de629b6eSShawn McCarney  */
222de629b6eSShawn McCarney template <typename Callback>
223de629b6eSShawn McCarney void getAllSensors(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
224de629b6eSShawn McCarney                    Callback&& callback)
225de629b6eSShawn McCarney {
226de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getAllSensors enter";
227de629b6eSShawn McCarney     const std::array<std::string, 1> interfaces = {
228de629b6eSShawn McCarney         "xyz.openbmc_project.Sensor.Value"};
229de629b6eSShawn McCarney 
230de629b6eSShawn McCarney     // Response handler for GetSubTreePaths DBus method
231de629b6eSShawn McCarney     auto respHandler = [callback{std::move(callback)}, SensorsAsyncResp](
232de629b6eSShawn McCarney                            const boost::system::error_code ec,
233de629b6eSShawn McCarney                            const std::vector<std::string>& sensorList) {
234de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "getAllSensors respHandler enter";
235de629b6eSShawn McCarney         if (ec)
236de629b6eSShawn McCarney         {
237de629b6eSShawn McCarney             messages::internalError(SensorsAsyncResp->res);
238de629b6eSShawn McCarney             BMCWEB_LOG_ERROR << "getAllSensors respHandler: DBus error " << ec;
239de629b6eSShawn McCarney             return;
240de629b6eSShawn McCarney         }
241de629b6eSShawn McCarney         boost::container::flat_set<std::string> sensorNames;
242de629b6eSShawn McCarney         for (const std::string& sensor : sensorList)
243de629b6eSShawn McCarney         {
244de629b6eSShawn McCarney             std::size_t lastPos = sensor.rfind("/");
245de629b6eSShawn McCarney             if (lastPos == std::string::npos)
246de629b6eSShawn McCarney             {
247de629b6eSShawn McCarney                 BMCWEB_LOG_ERROR << "Failed to find '/' in " << sensor;
248de629b6eSShawn McCarney                 continue;
249de629b6eSShawn McCarney             }
250de629b6eSShawn McCarney             std::string sensorName = sensor.substr(lastPos + 1);
251de629b6eSShawn McCarney             sensorNames.emplace(sensorName);
252de629b6eSShawn McCarney             BMCWEB_LOG_DEBUG << "Added sensor name " << sensorName;
253de629b6eSShawn McCarney         }
254de629b6eSShawn McCarney         callback(sensorNames);
255de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "getAllSensors respHandler exit";
256de629b6eSShawn McCarney     };
257de629b6eSShawn McCarney 
258de629b6eSShawn McCarney     // Query mapper for all DBus sensor object paths
259de629b6eSShawn McCarney     crow::connections::systemBus->async_method_call(
260de629b6eSShawn McCarney         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
261de629b6eSShawn McCarney         "/xyz/openbmc_project/object_mapper",
262de629b6eSShawn McCarney         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
263de629b6eSShawn McCarney         "/xyz/openbmc_project/sensors", int32_t(0), interfaces);
264de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getAllSensors exit";
265de629b6eSShawn McCarney }
266de629b6eSShawn McCarney 
267de629b6eSShawn McCarney /**
26808777fb0SLewanczyk, Dawid  * @brief Retrieves requested chassis sensors and redundancy data from DBus .
269588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
27008777fb0SLewanczyk, Dawid  * @param callback  Callback for next step in gathered sensor processing
27108777fb0SLewanczyk, Dawid  */
27208777fb0SLewanczyk, Dawid template <typename Callback>
273588c3f0dSKowalski, Kamil void getChassis(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
2741abe55efSEd Tanous                 Callback&& callback)
2751abe55efSEd Tanous {
27655c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis enter";
27708777fb0SLewanczyk, Dawid     // Process response from EntityManager and extract chassis data
2781abe55efSEd Tanous     auto respHandler = [callback{std::move(callback)},
2791abe55efSEd Tanous                         SensorsAsyncResp](const boost::system::error_code ec,
2801abe55efSEd Tanous                                           ManagedObjectsVectorType& resp) {
28155c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassis respHandler enter";
2821abe55efSEd Tanous         if (ec)
2831abe55efSEd Tanous         {
28455c7b7a2SEd Tanous             BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec;
2855f7d88c4SEd Tanous             messages::internalError(SensorsAsyncResp->res);
28608777fb0SLewanczyk, Dawid             return;
28708777fb0SLewanczyk, Dawid         }
28808777fb0SLewanczyk, Dawid         boost::container::flat_set<std::string> sensorNames;
28908777fb0SLewanczyk, Dawid 
290588c3f0dSKowalski, Kamil         //   SensorsAsyncResp->chassisId
291daf36e2eSEd Tanous         bool foundChassis = false;
292daf36e2eSEd Tanous         std::vector<std::string> split;
293daf36e2eSEd Tanous         // Reserve space for
294daf36e2eSEd Tanous         // /xyz/openbmc_project/inventory/<name>/<subname> + 3 subnames
295daf36e2eSEd Tanous         split.reserve(8);
296daf36e2eSEd Tanous 
2971abe55efSEd Tanous         for (const auto& objDictEntry : resp)
2981abe55efSEd Tanous         {
299daf36e2eSEd Tanous             const std::string& objectPath =
300daf36e2eSEd Tanous                 static_cast<const std::string&>(objDictEntry.first);
301daf36e2eSEd Tanous             boost::algorithm::split(split, objectPath, boost::is_any_of("/"));
3021abe55efSEd Tanous             if (split.size() < 2)
3031abe55efSEd Tanous             {
3041abe55efSEd Tanous                 BMCWEB_LOG_ERROR << "Got path that isn't long enough "
3051abe55efSEd Tanous                                  << objectPath;
306daf36e2eSEd Tanous                 split.clear();
307daf36e2eSEd Tanous                 continue;
308daf36e2eSEd Tanous             }
309daf36e2eSEd Tanous             const std::string& sensorName = split.end()[-1];
310daf36e2eSEd Tanous             const std::string& chassisName = split.end()[-2];
311daf36e2eSEd Tanous 
3121abe55efSEd Tanous             if (chassisName != SensorsAsyncResp->chassisId)
3131abe55efSEd Tanous             {
314daf36e2eSEd Tanous                 split.clear();
315daf36e2eSEd Tanous                 continue;
316daf36e2eSEd Tanous             }
31755c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "New sensor: " << sensorName;
318daf36e2eSEd Tanous             foundChassis = true;
31908777fb0SLewanczyk, Dawid             sensorNames.emplace(sensorName);
320daf36e2eSEd Tanous             split.clear();
32108777fb0SLewanczyk, Dawid         };
32255c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << sensorNames.size() << " Sensor names";
32308777fb0SLewanczyk, Dawid 
3241abe55efSEd Tanous         if (!foundChassis)
3251abe55efSEd Tanous         {
32655c7b7a2SEd Tanous             BMCWEB_LOG_INFO << "Unable to find chassis named "
327588c3f0dSKowalski, Kamil                             << SensorsAsyncResp->chassisId;
328f12894f8SJason M. Bills             messages::resourceNotFound(SensorsAsyncResp->res, "Chassis",
329f12894f8SJason M. Bills                                        SensorsAsyncResp->chassisId);
3301abe55efSEd Tanous         }
3311abe55efSEd Tanous         else
3321abe55efSEd Tanous         {
33308777fb0SLewanczyk, Dawid             callback(sensorNames);
33408777fb0SLewanczyk, Dawid         }
33555c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassis respHandler exit";
33608777fb0SLewanczyk, Dawid     };
33708777fb0SLewanczyk, Dawid 
33808777fb0SLewanczyk, Dawid     // Make call to EntityManager to find all chassis objects
33955c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
34055c7b7a2SEd Tanous         respHandler, "xyz.openbmc_project.EntityManager", "/",
3417885954aSLewanczyk, Dawid         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
34255c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis exit";
34308777fb0SLewanczyk, Dawid }
34408777fb0SLewanczyk, Dawid 
34508777fb0SLewanczyk, Dawid /**
346de629b6eSShawn McCarney  * @brief Finds all DBus object paths that implement ObjectManager.
347de629b6eSShawn McCarney  *
348de629b6eSShawn McCarney  * Creates a mapping from the associated connection name to the object path.
349de629b6eSShawn McCarney  *
350de629b6eSShawn McCarney  * Finds the object paths asynchronously.  Invokes callback when information has
351de629b6eSShawn McCarney  * been obtained.
352de629b6eSShawn McCarney  *
353de629b6eSShawn McCarney  * The callback must have the following signature:
354de629b6eSShawn McCarney  *   @code
355de629b6eSShawn McCarney  *   callback(const boost::container::flat_map<std::string,
356de629b6eSShawn McCarney  *            std::string>& objectMgrPaths)
357de629b6eSShawn McCarney  *   @endcode
358de629b6eSShawn McCarney  *
359de629b6eSShawn McCarney  * @param SensorsAsyncResp Pointer to object holding response data.
360de629b6eSShawn McCarney  * @param callback Callback to invoke when object paths obtained.
361de629b6eSShawn McCarney  */
362de629b6eSShawn McCarney template <typename Callback>
363de629b6eSShawn McCarney void getObjectManagerPaths(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
364de629b6eSShawn McCarney                            Callback&& callback)
365de629b6eSShawn McCarney {
366de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getObjectManagerPaths enter";
367de629b6eSShawn McCarney     const std::array<std::string, 1> interfaces = {
368de629b6eSShawn McCarney         "org.freedesktop.DBus.ObjectManager"};
369de629b6eSShawn McCarney 
370de629b6eSShawn McCarney     // Response handler for GetSubTree DBus method
371de629b6eSShawn McCarney     auto respHandler = [callback{std::move(callback)},
372de629b6eSShawn McCarney                         SensorsAsyncResp](const boost::system::error_code ec,
373de629b6eSShawn McCarney                                           const GetSubTreeType& subtree) {
374de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler enter";
375de629b6eSShawn McCarney         if (ec)
376de629b6eSShawn McCarney         {
377de629b6eSShawn McCarney             messages::internalError(SensorsAsyncResp->res);
378de629b6eSShawn McCarney             BMCWEB_LOG_ERROR << "getObjectManagerPaths respHandler: DBus error "
379de629b6eSShawn McCarney                              << ec;
380de629b6eSShawn McCarney             return;
381de629b6eSShawn McCarney         }
382de629b6eSShawn McCarney 
383de629b6eSShawn McCarney         // Loop over returned object paths
384de629b6eSShawn McCarney         boost::container::flat_map<std::string, std::string> objectMgrPaths;
385de629b6eSShawn McCarney         for (const std::pair<
386de629b6eSShawn McCarney                  std::string,
387de629b6eSShawn McCarney                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
388de629b6eSShawn McCarney                  object : subtree)
389de629b6eSShawn McCarney         {
390de629b6eSShawn McCarney             // Loop over connections for current object path
391de629b6eSShawn McCarney             const std::string& objectPath = object.first;
392de629b6eSShawn McCarney             for (const std::pair<std::string, std::vector<std::string>>&
393de629b6eSShawn McCarney                      objData : object.second)
394de629b6eSShawn McCarney             {
395de629b6eSShawn McCarney                 // Add mapping from connection to object path
396de629b6eSShawn McCarney                 const std::string& connection = objData.first;
397de629b6eSShawn McCarney                 objectMgrPaths[connection] = objectPath;
398de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "Added mapping " << connection << " -> "
399de629b6eSShawn McCarney                                  << objectPath;
400de629b6eSShawn McCarney             }
401de629b6eSShawn McCarney         }
402de629b6eSShawn McCarney         callback(std::move(objectMgrPaths));
403de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler exit";
404de629b6eSShawn McCarney     };
405de629b6eSShawn McCarney 
406de629b6eSShawn McCarney     // Query mapper for all DBus object paths that implement ObjectManager
407de629b6eSShawn McCarney     crow::connections::systemBus->async_method_call(
408de629b6eSShawn McCarney         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
409de629b6eSShawn McCarney         "/xyz/openbmc_project/object_mapper",
410de629b6eSShawn McCarney         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
411de629b6eSShawn McCarney         interfaces);
412de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getObjectManagerPaths exit";
413de629b6eSShawn McCarney }
414de629b6eSShawn McCarney 
415de629b6eSShawn McCarney /**
41608777fb0SLewanczyk, Dawid  * @brief Builds a json sensor representation of a sensor.
41708777fb0SLewanczyk, Dawid  * @param sensorName  The name of the sensor to be built
418274fad5aSGunnar Mills  * @param sensorType  The type (temperature, fan_tach, etc) of the sensor to
41908777fb0SLewanczyk, Dawid  * build
42008777fb0SLewanczyk, Dawid  * @param interfacesDict  A dictionary of the interfaces and properties of said
42108777fb0SLewanczyk, Dawid  * interfaces to be built from
42208777fb0SLewanczyk, Dawid  * @param sensor_json  The json object to fill
42308777fb0SLewanczyk, Dawid  */
42408777fb0SLewanczyk, Dawid void objectInterfacesToJson(
42508777fb0SLewanczyk, Dawid     const std::string& sensorName, const std::string& sensorType,
42608777fb0SLewanczyk, Dawid     const boost::container::flat_map<
427aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>&
42808777fb0SLewanczyk, Dawid         interfacesDict,
4291abe55efSEd Tanous     nlohmann::json& sensor_json)
4301abe55efSEd Tanous {
43108777fb0SLewanczyk, Dawid     // We need a value interface before we can do anything with it
43255c7b7a2SEd Tanous     auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
4331abe55efSEd Tanous     if (valueIt == interfacesDict.end())
4341abe55efSEd Tanous     {
43555c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface";
43608777fb0SLewanczyk, Dawid         return;
43708777fb0SLewanczyk, Dawid     }
43808777fb0SLewanczyk, Dawid 
43908777fb0SLewanczyk, Dawid     // Assume values exist as is (10^0 == 1) if no scale exists
44008777fb0SLewanczyk, Dawid     int64_t scaleMultiplier = 0;
44108777fb0SLewanczyk, Dawid 
44255c7b7a2SEd Tanous     auto scaleIt = valueIt->second.find("Scale");
44308777fb0SLewanczyk, Dawid     // If a scale exists, pull value as int64, and use the scaling.
4441abe55efSEd Tanous     if (scaleIt != valueIt->second.end())
4451abe55efSEd Tanous     {
446abf2add6SEd Tanous         const int64_t* int64Value = std::get_if<int64_t>(&scaleIt->second);
4471abe55efSEd Tanous         if (int64Value != nullptr)
4481abe55efSEd Tanous         {
44908777fb0SLewanczyk, Dawid             scaleMultiplier = *int64Value;
45008777fb0SLewanczyk, Dawid         }
45108777fb0SLewanczyk, Dawid     }
45208777fb0SLewanczyk, Dawid 
45308777fb0SLewanczyk, Dawid     sensor_json["MemberId"] = sensorName;
45408777fb0SLewanczyk, Dawid     sensor_json["Name"] = sensorName;
45508777fb0SLewanczyk, Dawid     sensor_json["Status"]["State"] = "Enabled";
45608777fb0SLewanczyk, Dawid     sensor_json["Status"]["Health"] = "OK";
45708777fb0SLewanczyk, Dawid 
45808777fb0SLewanczyk, Dawid     // Parameter to set to override the type we get from dbus, and force it to
45908777fb0SLewanczyk, Dawid     // int, regardless of what is available.  This is used for schemas like fan,
46008777fb0SLewanczyk, Dawid     // that require integers, not floats.
46108777fb0SLewanczyk, Dawid     bool forceToInt = false;
46208777fb0SLewanczyk, Dawid 
46308777fb0SLewanczyk, Dawid     const char* unit = "Reading";
4641abe55efSEd Tanous     if (sensorType == "temperature")
4651abe55efSEd Tanous     {
46608777fb0SLewanczyk, Dawid         unit = "ReadingCelsius";
4677885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature";
46808777fb0SLewanczyk, Dawid         // TODO(ed) Documentation says that path should be type fan_tach,
46908777fb0SLewanczyk, Dawid         // implementation seems to implement fan
4701abe55efSEd Tanous     }
4711abe55efSEd Tanous     else if (sensorType == "fan" || sensorType == "fan_tach")
4721abe55efSEd Tanous     {
47308777fb0SLewanczyk, Dawid         unit = "Reading";
47408777fb0SLewanczyk, Dawid         sensor_json["ReadingUnits"] = "RPM";
4757885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
47608777fb0SLewanczyk, Dawid         forceToInt = true;
4771abe55efSEd Tanous     }
4786f6d0d32SEd Tanous     else if (sensorType == "fan_pwm")
4796f6d0d32SEd Tanous     {
4806f6d0d32SEd Tanous         unit = "Reading";
4816f6d0d32SEd Tanous         sensor_json["ReadingUnits"] = "Percent";
4826f6d0d32SEd Tanous         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
4836f6d0d32SEd Tanous         forceToInt = true;
4846f6d0d32SEd Tanous     }
4851abe55efSEd Tanous     else if (sensorType == "voltage")
4861abe55efSEd Tanous     {
48708777fb0SLewanczyk, Dawid         unit = "ReadingVolts";
4887885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage";
4891abe55efSEd Tanous     }
4902474adfaSEd Tanous     else if (sensorType == "power")
4912474adfaSEd Tanous     {
4922474adfaSEd Tanous         unit = "LastPowerOutputWatts";
4932474adfaSEd Tanous     }
4941abe55efSEd Tanous     else
4951abe55efSEd Tanous     {
49655c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
49708777fb0SLewanczyk, Dawid         return;
49808777fb0SLewanczyk, Dawid     }
49908777fb0SLewanczyk, Dawid     // Map of dbus interface name, dbus property name and redfish property_name
50008777fb0SLewanczyk, Dawid     std::vector<std::tuple<const char*, const char*, const char*>> properties;
50108777fb0SLewanczyk, Dawid     properties.reserve(7);
50208777fb0SLewanczyk, Dawid 
50308777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
504de629b6eSShawn McCarney 
505de629b6eSShawn McCarney     // If sensor type doesn't map to Redfish PowerSupply, add threshold props
506de629b6eSShawn McCarney     if ((sensorType != "current") && (sensorType != "power"))
507de629b6eSShawn McCarney     {
50808777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
50908777fb0SLewanczyk, Dawid                                 "WarningHigh", "UpperThresholdNonCritical");
51008777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
51108777fb0SLewanczyk, Dawid                                 "WarningLow", "LowerThresholdNonCritical");
51208777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
51308777fb0SLewanczyk, Dawid                                 "CriticalHigh", "UpperThresholdCritical");
51408777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
51508777fb0SLewanczyk, Dawid                                 "CriticalLow", "LowerThresholdCritical");
516de629b6eSShawn McCarney     }
51708777fb0SLewanczyk, Dawid 
5182474adfaSEd Tanous     // TODO Need to get UpperThresholdFatal and LowerThresholdFatal
5192474adfaSEd Tanous 
5201abe55efSEd Tanous     if (sensorType == "temperature")
5211abe55efSEd Tanous     {
52208777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
52308777fb0SLewanczyk, Dawid                                 "MinReadingRangeTemp");
52408777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
52508777fb0SLewanczyk, Dawid                                 "MaxReadingRangeTemp");
5261abe55efSEd Tanous     }
527de629b6eSShawn McCarney     else if ((sensorType != "current") && (sensorType != "power"))
5281abe55efSEd Tanous     {
529de629b6eSShawn McCarney         // Sensor type doesn't map to Redfish PowerSupply; add min/max props
53008777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
53108777fb0SLewanczyk, Dawid                                 "MinReadingRange");
53208777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
53308777fb0SLewanczyk, Dawid                                 "MaxReadingRange");
53408777fb0SLewanczyk, Dawid     }
53508777fb0SLewanczyk, Dawid 
53608777fb0SLewanczyk, Dawid     for (const std::tuple<const char*, const char*, const char*>& p :
5371abe55efSEd Tanous          properties)
5381abe55efSEd Tanous     {
53908777fb0SLewanczyk, Dawid         auto interfaceProperties = interfacesDict.find(std::get<0>(p));
5401abe55efSEd Tanous         if (interfaceProperties != interfacesDict.end())
5411abe55efSEd Tanous         {
542b01bf299SEd Tanous             auto valueIt = interfaceProperties->second.find(std::get<1>(p));
543b01bf299SEd Tanous             if (valueIt != interfaceProperties->second.end())
5441abe55efSEd Tanous             {
545b01bf299SEd Tanous                 const SensorVariant& valueVariant = valueIt->second;
546b01bf299SEd Tanous                 nlohmann::json& valueIt = sensor_json[std::get<2>(p)];
54708777fb0SLewanczyk, Dawid                 // Attempt to pull the int64 directly
548abf2add6SEd Tanous                 const int64_t* int64Value = std::get_if<int64_t>(&valueVariant);
54908777fb0SLewanczyk, Dawid 
550abf2add6SEd Tanous                 const double* doubleValue = std::get_if<double>(&valueVariant);
5516f6d0d32SEd Tanous                 double temp = 0.0;
5526f6d0d32SEd Tanous                 if (int64Value != nullptr)
5531abe55efSEd Tanous                 {
5546f6d0d32SEd Tanous                     temp = *int64Value;
5556f6d0d32SEd Tanous                 }
5566f6d0d32SEd Tanous                 else if (doubleValue != nullptr)
5571abe55efSEd Tanous                 {
5586f6d0d32SEd Tanous                     temp = *doubleValue;
5591abe55efSEd Tanous                 }
5601abe55efSEd Tanous                 else
5611abe55efSEd Tanous                 {
5626f6d0d32SEd Tanous                     BMCWEB_LOG_ERROR
5636f6d0d32SEd Tanous                         << "Got value interface that wasn't int or double";
5646f6d0d32SEd Tanous                     continue;
56508777fb0SLewanczyk, Dawid                 }
5666f6d0d32SEd Tanous                 temp = temp * std::pow(10, scaleMultiplier);
5676f6d0d32SEd Tanous                 if (forceToInt)
5686f6d0d32SEd Tanous                 {
569b01bf299SEd Tanous                     valueIt = static_cast<int64_t>(temp);
5706f6d0d32SEd Tanous                 }
5716f6d0d32SEd Tanous                 else
5726f6d0d32SEd Tanous                 {
573b01bf299SEd Tanous                     valueIt = temp;
57408777fb0SLewanczyk, Dawid                 }
57508777fb0SLewanczyk, Dawid             }
57608777fb0SLewanczyk, Dawid         }
57708777fb0SLewanczyk, Dawid     }
57855c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
57908777fb0SLewanczyk, Dawid }
58008777fb0SLewanczyk, Dawid 
5818bd25ccdSJames Feist static void
5828bd25ccdSJames Feist     populateFanRedundancy(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp)
5838bd25ccdSJames Feist {
5848bd25ccdSJames Feist     crow::connections::systemBus->async_method_call(
5858bd25ccdSJames Feist         [sensorsAsyncResp](const boost::system::error_code ec,
5868bd25ccdSJames Feist                            const GetSubTreeType& resp) {
5878bd25ccdSJames Feist             if (ec)
5888bd25ccdSJames Feist             {
5898bd25ccdSJames Feist                 return; // don't have to have this interface
5908bd25ccdSJames Feist             }
591*e278c18fSEd Tanous             for (const std::pair<std::string,
592*e278c18fSEd Tanous                                  std::vector<std::pair<
593*e278c18fSEd Tanous                                      std::string, std::vector<std::string>>>>&
594*e278c18fSEd Tanous                      pathPair : resp)
5958bd25ccdSJames Feist             {
596*e278c18fSEd Tanous                 const std::string& path = pathPair.first;
597*e278c18fSEd Tanous                 const std::vector<
598*e278c18fSEd Tanous                     std::pair<std::string, std::vector<std::string>>>& objDict =
599*e278c18fSEd Tanous                     pathPair.second;
6008bd25ccdSJames Feist                 if (objDict.empty())
6018bd25ccdSJames Feist                 {
6028bd25ccdSJames Feist                     continue; // this should be impossible
6038bd25ccdSJames Feist                 }
6048bd25ccdSJames Feist 
6058bd25ccdSJames Feist                 const std::string& owner = objDict.begin()->first;
6068bd25ccdSJames Feist                 crow::connections::systemBus->async_method_call(
6078bd25ccdSJames Feist                     [path, owner,
6088bd25ccdSJames Feist                      sensorsAsyncResp](const boost::system::error_code ec,
6098bd25ccdSJames Feist                                        std::variant<std::vector<std::string>>
6108bd25ccdSJames Feist                                            variantEndpoints) {
6118bd25ccdSJames Feist                         if (ec)
6128bd25ccdSJames Feist                         {
6138bd25ccdSJames Feist                             return; // if they don't have an association we
6148bd25ccdSJames Feist                                     // can't tell what chassis is
6158bd25ccdSJames Feist                         }
6168bd25ccdSJames Feist                         // verify part of the right chassis
6178bd25ccdSJames Feist                         auto endpoints = std::get_if<std::vector<std::string>>(
6188bd25ccdSJames Feist                             &variantEndpoints);
6198bd25ccdSJames Feist 
6208bd25ccdSJames Feist                         if (endpoints == nullptr)
6218bd25ccdSJames Feist                         {
6228bd25ccdSJames Feist                             BMCWEB_LOG_ERROR << "Invalid association interface";
6238bd25ccdSJames Feist                             messages::internalError(sensorsAsyncResp->res);
6248bd25ccdSJames Feist                             return;
6258bd25ccdSJames Feist                         }
6268bd25ccdSJames Feist 
6278bd25ccdSJames Feist                         auto found = std::find_if(
6288bd25ccdSJames Feist                             endpoints->begin(), endpoints->end(),
6298bd25ccdSJames Feist                             [sensorsAsyncResp](const std::string& entry) {
6308bd25ccdSJames Feist                                 return entry.find(
6318bd25ccdSJames Feist                                            sensorsAsyncResp->chassisId) !=
6328bd25ccdSJames Feist                                        std::string::npos;
6338bd25ccdSJames Feist                             });
6348bd25ccdSJames Feist 
6358bd25ccdSJames Feist                         if (found == endpoints->end())
6368bd25ccdSJames Feist                         {
6378bd25ccdSJames Feist                             return;
6388bd25ccdSJames Feist                         }
6398bd25ccdSJames Feist                         crow::connections::systemBus->async_method_call(
6408bd25ccdSJames Feist                             [path, sensorsAsyncResp](
6418bd25ccdSJames Feist                                 const boost::system::error_code ec,
6428bd25ccdSJames Feist                                 const boost::container::flat_map<
6438bd25ccdSJames Feist                                     std::string,
6448bd25ccdSJames Feist                                     std::variant<uint8_t,
6458bd25ccdSJames Feist                                                  std::vector<std::string>,
6468bd25ccdSJames Feist                                                  std::string>>& ret) {
6478bd25ccdSJames Feist                                 if (ec)
6488bd25ccdSJames Feist                                 {
6498bd25ccdSJames Feist                                     return; // don't have to have this
6508bd25ccdSJames Feist                                             // interface
6518bd25ccdSJames Feist                                 }
6528bd25ccdSJames Feist                                 auto findFailures = ret.find("AllowedFailures");
6538bd25ccdSJames Feist                                 auto findCollection = ret.find("Collection");
6548bd25ccdSJames Feist                                 auto findStatus = ret.find("Status");
6558bd25ccdSJames Feist 
6568bd25ccdSJames Feist                                 if (findFailures == ret.end() ||
6578bd25ccdSJames Feist                                     findCollection == ret.end() ||
6588bd25ccdSJames Feist                                     findStatus == ret.end())
6598bd25ccdSJames Feist                                 {
6608bd25ccdSJames Feist                                     BMCWEB_LOG_ERROR
6618bd25ccdSJames Feist                                         << "Invalid redundancy interface";
6628bd25ccdSJames Feist                                     messages::internalError(
6638bd25ccdSJames Feist                                         sensorsAsyncResp->res);
6648bd25ccdSJames Feist                                     return;
6658bd25ccdSJames Feist                                 }
6668bd25ccdSJames Feist 
6678bd25ccdSJames Feist                                 auto allowedFailures = std::get_if<uint8_t>(
6688bd25ccdSJames Feist                                     &(findFailures->second));
6698bd25ccdSJames Feist                                 auto collection =
6708bd25ccdSJames Feist                                     std::get_if<std::vector<std::string>>(
6718bd25ccdSJames Feist                                         &(findCollection->second));
6728bd25ccdSJames Feist                                 auto status = std::get_if<std::string>(
6738bd25ccdSJames Feist                                     &(findStatus->second));
6748bd25ccdSJames Feist 
6758bd25ccdSJames Feist                                 if (allowedFailures == nullptr ||
6768bd25ccdSJames Feist                                     collection == nullptr || status == nullptr)
6778bd25ccdSJames Feist                                 {
6788bd25ccdSJames Feist 
6798bd25ccdSJames Feist                                     BMCWEB_LOG_ERROR
6808bd25ccdSJames Feist                                         << "Invalid redundancy interface "
6818bd25ccdSJames Feist                                            "types";
6828bd25ccdSJames Feist                                     messages::internalError(
6838bd25ccdSJames Feist                                         sensorsAsyncResp->res);
6848bd25ccdSJames Feist                                     return;
6858bd25ccdSJames Feist                                 }
6868bd25ccdSJames Feist                                 size_t lastSlash = path.rfind("/");
6878bd25ccdSJames Feist                                 if (lastSlash == std::string::npos)
6888bd25ccdSJames Feist                                 {
6898bd25ccdSJames Feist                                     // this should be impossible
6908bd25ccdSJames Feist                                     messages::internalError(
6918bd25ccdSJames Feist                                         sensorsAsyncResp->res);
6928bd25ccdSJames Feist                                     return;
6938bd25ccdSJames Feist                                 }
6948bd25ccdSJames Feist                                 std::string name = path.substr(lastSlash + 1);
6958bd25ccdSJames Feist                                 std::replace(name.begin(), name.end(), '_',
6968bd25ccdSJames Feist                                              ' ');
6978bd25ccdSJames Feist 
6988bd25ccdSJames Feist                                 std::string health;
6998bd25ccdSJames Feist 
7008bd25ccdSJames Feist                                 if (boost::ends_with(*status, "Full"))
7018bd25ccdSJames Feist                                 {
7028bd25ccdSJames Feist                                     health = "OK";
7038bd25ccdSJames Feist                                 }
7048bd25ccdSJames Feist                                 else if (boost::ends_with(*status, "Degraded"))
7058bd25ccdSJames Feist                                 {
7068bd25ccdSJames Feist                                     health = "Warning";
7078bd25ccdSJames Feist                                 }
7088bd25ccdSJames Feist                                 else
7098bd25ccdSJames Feist                                 {
7108bd25ccdSJames Feist                                     health = "Critical";
7118bd25ccdSJames Feist                                 }
7128bd25ccdSJames Feist                                 std::vector<nlohmann::json> redfishCollection;
7138bd25ccdSJames Feist                                 const auto& fanRedfish =
7148bd25ccdSJames Feist                                     sensorsAsyncResp->res.jsonValue["Fans"];
7158bd25ccdSJames Feist                                 for (const std::string& item : *collection)
7168bd25ccdSJames Feist                                 {
7178bd25ccdSJames Feist                                     lastSlash = item.rfind("/");
7188bd25ccdSJames Feist                                     // make a copy as collection is const
7198bd25ccdSJames Feist                                     std::string itemName =
7208bd25ccdSJames Feist                                         item.substr(lastSlash + 1);
7218bd25ccdSJames Feist                                     /*
7228bd25ccdSJames Feist                                     todo(ed): merge patch that fixes the names
7238bd25ccdSJames Feist                                     std::replace(itemName.begin(),
7248bd25ccdSJames Feist                                                  itemName.end(), '_', ' ');*/
7258bd25ccdSJames Feist                                     auto schemaItem = std::find_if(
7268bd25ccdSJames Feist                                         fanRedfish.begin(), fanRedfish.end(),
7278bd25ccdSJames Feist                                         [itemName](const nlohmann::json& fan) {
7288bd25ccdSJames Feist                                             return fan["MemberId"] == itemName;
7298bd25ccdSJames Feist                                         });
7308bd25ccdSJames Feist                                     if (schemaItem != fanRedfish.end())
7318bd25ccdSJames Feist                                     {
7328bd25ccdSJames Feist                                         redfishCollection.push_back(
7338bd25ccdSJames Feist                                             {{"@odata.id",
7348bd25ccdSJames Feist                                               (*schemaItem)["@odata.id"]}});
7358bd25ccdSJames Feist                                     }
7368bd25ccdSJames Feist                                     else
7378bd25ccdSJames Feist                                     {
7388bd25ccdSJames Feist                                         BMCWEB_LOG_ERROR
7398bd25ccdSJames Feist                                             << "failed to find fan in schema";
7408bd25ccdSJames Feist                                         messages::internalError(
7418bd25ccdSJames Feist                                             sensorsAsyncResp->res);
7428bd25ccdSJames Feist                                         return;
7438bd25ccdSJames Feist                                     }
7448bd25ccdSJames Feist                                 }
7458bd25ccdSJames Feist 
7468bd25ccdSJames Feist                                 auto& resp = sensorsAsyncResp->res
7478bd25ccdSJames Feist                                                  .jsonValue["Redundancy"];
7488bd25ccdSJames Feist                                 resp.push_back(
7498bd25ccdSJames Feist                                     {{"@odata.id",
7508bd25ccdSJames Feist                                       "/refish/v1/Chassis/" +
7518bd25ccdSJames Feist                                           sensorsAsyncResp->chassisId + "/" +
7528bd25ccdSJames Feist                                           sensorsAsyncResp->chassisSubNode +
7538bd25ccdSJames Feist                                           "#/Redundancy/" +
7548bd25ccdSJames Feist                                           std::to_string(resp.size())},
7558bd25ccdSJames Feist                                      {"@odata.type",
7568bd25ccdSJames Feist                                       "#Redundancy.v1_3_2.Redundancy"},
7578bd25ccdSJames Feist                                      {"MinNumNeeded",
7588bd25ccdSJames Feist                                       collection->size() - *allowedFailures},
7598bd25ccdSJames Feist                                      {"MemberId", name},
7608bd25ccdSJames Feist                                      {"Mode", "N+m"},
7618bd25ccdSJames Feist                                      {"Name", name},
7628bd25ccdSJames Feist                                      {"RedundancySet", redfishCollection},
7638bd25ccdSJames Feist                                      {"Status",
7648bd25ccdSJames Feist                                       {{"Health", health},
7658bd25ccdSJames Feist                                        {"State", "Enabled"}}}});
7668bd25ccdSJames Feist                             },
7678bd25ccdSJames Feist                             owner, path, "org.freedesktop.DBus.Properties",
7688bd25ccdSJames Feist                             "GetAll",
7698bd25ccdSJames Feist                             "xyz.openbmc_project.Control.FanRedundancy");
7708bd25ccdSJames Feist                     },
7718bd25ccdSJames Feist                     "xyz.openbmc_project.ObjectMapper", path + "/inventory",
7728bd25ccdSJames Feist                     "org.freedesktop.DBus.Properties", "Get",
7738bd25ccdSJames Feist                     "xyz.openbmc_project.Association", "endpoints");
7748bd25ccdSJames Feist             }
7758bd25ccdSJames Feist         },
7768bd25ccdSJames Feist         "xyz.openbmc_project.ObjectMapper",
7778bd25ccdSJames Feist         "/xyz/openbmc_project/object_mapper",
7788bd25ccdSJames Feist         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
7798bd25ccdSJames Feist         "/xyz/openbmc_project/control", 2,
7808bd25ccdSJames Feist         std::array<const char*, 1>{
7818bd25ccdSJames Feist             "xyz.openbmc_project.Control.FanRedundancy"});
7828bd25ccdSJames Feist }
7838bd25ccdSJames Feist 
78408777fb0SLewanczyk, Dawid /**
785de629b6eSShawn McCarney  * @brief Gets the values of the specified sensors.
786de629b6eSShawn McCarney  *
787de629b6eSShawn McCarney  * Stores the results as JSON in the SensorsAsyncResp.
788de629b6eSShawn McCarney  *
789de629b6eSShawn McCarney  * Gets the sensor values asynchronously.  Stores the results later when the
790de629b6eSShawn McCarney  * information has been obtained.
791de629b6eSShawn McCarney  *
792de629b6eSShawn McCarney  * The sensorNames set contains all sensors for the current chassis.
793de629b6eSShawn McCarney  * SensorsAsyncResp contains the requested sensor types.  Only sensors of a
794de629b6eSShawn McCarney  * requested type are included in the JSON output.
795de629b6eSShawn McCarney  *
796de629b6eSShawn McCarney  * To minimize the number of DBus calls, the DBus method
797de629b6eSShawn McCarney  * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
798de629b6eSShawn McCarney  * values of all sensors provided by a connection (service).
799de629b6eSShawn McCarney  *
800de629b6eSShawn McCarney  * The connections set contains all the connections that provide sensor values.
801de629b6eSShawn McCarney  *
802de629b6eSShawn McCarney  * The objectMgrPaths map contains mappings from a connection name to the
803de629b6eSShawn McCarney  * corresponding DBus object path that implements ObjectManager.
804de629b6eSShawn McCarney  *
805de629b6eSShawn McCarney  * @param SensorsAsyncResp Pointer to object holding response data.
806de629b6eSShawn McCarney  * @param sensorNames All sensors within the current chassis.
807de629b6eSShawn McCarney  * @param connections Connections that provide sensor values.
808de629b6eSShawn McCarney  * @param objectMgrPaths Mappings from connection name to DBus object path that
809de629b6eSShawn McCarney  * implements ObjectManager.
810de629b6eSShawn McCarney  */
811de629b6eSShawn McCarney void getSensorData(
812de629b6eSShawn McCarney     std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
813de629b6eSShawn McCarney     const boost::container::flat_set<std::string>& sensorNames,
814de629b6eSShawn McCarney     const boost::container::flat_set<std::string>& connections,
815de629b6eSShawn McCarney     const boost::container::flat_map<std::string, std::string>& objectMgrPaths)
816de629b6eSShawn McCarney {
817de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getSensorData enter";
818de629b6eSShawn McCarney     // Get managed objects from all services exposing sensors
819de629b6eSShawn McCarney     for (const std::string& connection : connections)
820de629b6eSShawn McCarney     {
821de629b6eSShawn McCarney         // Response handler to process managed objects
822de629b6eSShawn McCarney         auto getManagedObjectsCb = [&, SensorsAsyncResp, sensorNames](
823de629b6eSShawn McCarney                                        const boost::system::error_code ec,
824de629b6eSShawn McCarney                                        ManagedObjectsVectorType& resp) {
825de629b6eSShawn McCarney             BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
826de629b6eSShawn McCarney             if (ec)
827de629b6eSShawn McCarney             {
828de629b6eSShawn McCarney                 BMCWEB_LOG_ERROR << "getManagedObjectsCb DBUS error: " << ec;
829de629b6eSShawn McCarney                 messages::internalError(SensorsAsyncResp->res);
830de629b6eSShawn McCarney                 return;
831de629b6eSShawn McCarney             }
832de629b6eSShawn McCarney             // Go through all objects and update response with sensor data
833de629b6eSShawn McCarney             for (const auto& objDictEntry : resp)
834de629b6eSShawn McCarney             {
835de629b6eSShawn McCarney                 const std::string& objPath =
836de629b6eSShawn McCarney                     static_cast<const std::string&>(objDictEntry.first);
837de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "getManagedObjectsCb parsing object "
838de629b6eSShawn McCarney                                  << objPath;
839de629b6eSShawn McCarney 
840de629b6eSShawn McCarney                 // Skip sensor if it is not one of the requested types
841de629b6eSShawn McCarney                 if (!isRequestedSensorType(objPath, SensorsAsyncResp))
842de629b6eSShawn McCarney                 {
843de629b6eSShawn McCarney                     continue;
844de629b6eSShawn McCarney                 }
845de629b6eSShawn McCarney 
846de629b6eSShawn McCarney                 std::vector<std::string> split;
847de629b6eSShawn McCarney                 // Reserve space for
848de629b6eSShawn McCarney                 // /xyz/openbmc_project/sensors/<name>/<subname>
849de629b6eSShawn McCarney                 split.reserve(6);
850de629b6eSShawn McCarney                 boost::algorithm::split(split, objPath, boost::is_any_of("/"));
851de629b6eSShawn McCarney                 if (split.size() < 6)
852de629b6eSShawn McCarney                 {
853de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << "Got path that isn't long enough "
854de629b6eSShawn McCarney                                      << objPath;
855de629b6eSShawn McCarney                     continue;
856de629b6eSShawn McCarney                 }
857de629b6eSShawn McCarney                 // These indexes aren't intuitive, as boost::split puts an empty
858de629b6eSShawn McCarney                 // string at the beginning
859de629b6eSShawn McCarney                 const std::string& sensorType = split[4];
860de629b6eSShawn McCarney                 const std::string& sensorName = split[5];
861de629b6eSShawn McCarney                 BMCWEB_LOG_DEBUG << "sensorName " << sensorName
862de629b6eSShawn McCarney                                  << " sensorType " << sensorType;
863de629b6eSShawn McCarney                 if (sensorNames.find(sensorName) == sensorNames.end())
864de629b6eSShawn McCarney                 {
865de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << sensorName << " not in sensor list ";
866de629b6eSShawn McCarney                     continue;
867de629b6eSShawn McCarney                 }
868de629b6eSShawn McCarney 
869de629b6eSShawn McCarney                 const char* fieldName = nullptr;
870de629b6eSShawn McCarney                 if (sensorType == "temperature")
871de629b6eSShawn McCarney                 {
872de629b6eSShawn McCarney                     fieldName = "Temperatures";
873de629b6eSShawn McCarney                 }
874de629b6eSShawn McCarney                 else if (sensorType == "fan" || sensorType == "fan_tach" ||
875de629b6eSShawn McCarney                          sensorType == "fan_pwm")
876de629b6eSShawn McCarney                 {
877de629b6eSShawn McCarney                     fieldName = "Fans";
878de629b6eSShawn McCarney                 }
879de629b6eSShawn McCarney                 else if (sensorType == "voltage")
880de629b6eSShawn McCarney                 {
881de629b6eSShawn McCarney                     fieldName = "Voltages";
882de629b6eSShawn McCarney                 }
883de629b6eSShawn McCarney                 else if (sensorType == "current")
884de629b6eSShawn McCarney                 {
885de629b6eSShawn McCarney                     fieldName = "PowerSupplies";
886de629b6eSShawn McCarney                 }
887de629b6eSShawn McCarney                 else if (sensorType == "power")
888de629b6eSShawn McCarney                 {
889de629b6eSShawn McCarney                     fieldName = "PowerSupplies";
890de629b6eSShawn McCarney                 }
891de629b6eSShawn McCarney                 else
892de629b6eSShawn McCarney                 {
893de629b6eSShawn McCarney                     BMCWEB_LOG_ERROR << "Unsure how to handle sensorType "
894de629b6eSShawn McCarney                                      << sensorType;
895de629b6eSShawn McCarney                     continue;
896de629b6eSShawn McCarney                 }
897de629b6eSShawn McCarney 
898de629b6eSShawn McCarney                 nlohmann::json& tempArray =
899de629b6eSShawn McCarney                     SensorsAsyncResp->res.jsonValue[fieldName];
900de629b6eSShawn McCarney 
901de629b6eSShawn McCarney                 tempArray.push_back(
902de629b6eSShawn McCarney                     {{"@odata.id",
903de629b6eSShawn McCarney                       "/redfish/v1/Chassis/" + SensorsAsyncResp->chassisId +
904de629b6eSShawn McCarney                           "/" + SensorsAsyncResp->chassisSubNode + "#/" +
905de629b6eSShawn McCarney                           fieldName + "/" + std::to_string(tempArray.size())}});
906de629b6eSShawn McCarney                 nlohmann::json& sensorJson = tempArray.back();
907de629b6eSShawn McCarney 
908de629b6eSShawn McCarney                 objectInterfacesToJson(sensorName, sensorType,
909de629b6eSShawn McCarney                                        objDictEntry.second, sensorJson);
910de629b6eSShawn McCarney             }
9118bd25ccdSJames Feist             if (SensorsAsyncResp.use_count() == 1 &&
9128bd25ccdSJames Feist                 SensorsAsyncResp->chassisSubNode == "Thermal")
9138bd25ccdSJames Feist             {
9148bd25ccdSJames Feist                 populateFanRedundancy(SensorsAsyncResp);
9158bd25ccdSJames Feist             }
916de629b6eSShawn McCarney             BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
917de629b6eSShawn McCarney         };
918de629b6eSShawn McCarney 
919de629b6eSShawn McCarney         // Find DBus object path that implements ObjectManager for the current
920de629b6eSShawn McCarney         // connection.  If no mapping found, default to "/".
921de629b6eSShawn McCarney         auto iter = objectMgrPaths.find(connection);
922de629b6eSShawn McCarney         const std::string& objectMgrPath =
923de629b6eSShawn McCarney             (iter != objectMgrPaths.end()) ? iter->second : "/";
924de629b6eSShawn McCarney         BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
925de629b6eSShawn McCarney                          << objectMgrPath;
926de629b6eSShawn McCarney 
927de629b6eSShawn McCarney         crow::connections::systemBus->async_method_call(
928de629b6eSShawn McCarney             getManagedObjectsCb, connection, objectMgrPath,
929de629b6eSShawn McCarney             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
930de629b6eSShawn McCarney     };
931de629b6eSShawn McCarney     BMCWEB_LOG_DEBUG << "getSensorData exit";
932de629b6eSShawn McCarney }
933de629b6eSShawn McCarney 
934de629b6eSShawn McCarney /**
93508777fb0SLewanczyk, Dawid  * @brief Entry point for retrieving sensors data related to requested
93608777fb0SLewanczyk, Dawid  *        chassis.
937588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
93808777fb0SLewanczyk, Dawid  */
9391abe55efSEd Tanous void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
9401abe55efSEd Tanous {
94155c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisData enter";
942588c3f0dSKowalski, Kamil     auto getChassisCb = [&, SensorsAsyncResp](
943588c3f0dSKowalski, Kamil                             boost::container::flat_set<std::string>&
94408777fb0SLewanczyk, Dawid                                 sensorNames) {
94555c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassisCb enter";
946588c3f0dSKowalski, Kamil         auto getConnectionCb =
947588c3f0dSKowalski, Kamil             [&, SensorsAsyncResp, sensorNames](
948588c3f0dSKowalski, Kamil                 const boost::container::flat_set<std::string>& connections) {
94955c7b7a2SEd Tanous                 BMCWEB_LOG_DEBUG << "getConnectionCb enter";
950de629b6eSShawn McCarney                 auto getObjectManagerPathsCb =
951de629b6eSShawn McCarney                     [SensorsAsyncResp, sensorNames,
952de629b6eSShawn McCarney                      connections](const boost::container::flat_map<
953de629b6eSShawn McCarney                                   std::string, std::string>& objectMgrPaths) {
954de629b6eSShawn McCarney                         BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb enter";
955de629b6eSShawn McCarney                         // Get sensor data and store results in JSON response
956de629b6eSShawn McCarney                         getSensorData(SensorsAsyncResp, sensorNames,
957de629b6eSShawn McCarney                                       connections, objectMgrPaths);
958de629b6eSShawn McCarney                         BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb exit";
95908777fb0SLewanczyk, Dawid                     };
960de629b6eSShawn McCarney 
961de629b6eSShawn McCarney                 // Get mapping from connection names to the DBus object paths
962de629b6eSShawn McCarney                 // that implement the ObjectManager interface
963de629b6eSShawn McCarney                 getObjectManagerPaths(SensorsAsyncResp,
964de629b6eSShawn McCarney                                       std::move(getObjectManagerPathsCb));
96555c7b7a2SEd Tanous                 BMCWEB_LOG_DEBUG << "getConnectionCb exit";
96608777fb0SLewanczyk, Dawid             };
967de629b6eSShawn McCarney 
968de629b6eSShawn McCarney         // Get set of connections that provide sensor values
9691abe55efSEd Tanous         getConnections(SensorsAsyncResp, sensorNames,
9701abe55efSEd Tanous                        std::move(getConnectionCb));
97155c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassisCb exit";
97208777fb0SLewanczyk, Dawid     };
97308777fb0SLewanczyk, Dawid 
974de629b6eSShawn McCarney #ifdef BMCWEB_ENABLE_REDFISH_ONE_CHASSIS
975de629b6eSShawn McCarney     // Get all sensor names
976de629b6eSShawn McCarney     getAllSensors(SensorsAsyncResp, std::move(getChassisCb));
977de629b6eSShawn McCarney #else
978de629b6eSShawn McCarney     // Get sensor names in chassis
979588c3f0dSKowalski, Kamil     getChassis(SensorsAsyncResp, std::move(getChassisCb));
980de629b6eSShawn McCarney #endif
98155c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisData exit";
98208777fb0SLewanczyk, Dawid };
98308777fb0SLewanczyk, Dawid 
984413961deSRichard Marian Thomaiyar /**
985413961deSRichard Marian Thomaiyar  * @brief Entry point for overriding sensor values of given sensor
986413961deSRichard Marian Thomaiyar  *
987413961deSRichard Marian Thomaiyar  * @param res   response object
988413961deSRichard Marian Thomaiyar  * @param req   request object
989413961deSRichard Marian Thomaiyar  * @param params   parameter passed for CRUD
990413961deSRichard Marian Thomaiyar  * @param typeList   TypeList of sensors for the resource queried
991413961deSRichard Marian Thomaiyar  * @param chassisSubNode   Chassis Node for which the query has to happen
992413961deSRichard Marian Thomaiyar  */
993413961deSRichard Marian Thomaiyar void setSensorOverride(crow::Response& res, const crow::Request& req,
994413961deSRichard Marian Thomaiyar                        const std::vector<std::string>& params,
995b01bf299SEd Tanous                        const std::initializer_list<const char*> typeList,
996413961deSRichard Marian Thomaiyar                        const std::string& chassisSubNode)
997413961deSRichard Marian Thomaiyar {
998413961deSRichard Marian Thomaiyar 
999413961deSRichard Marian Thomaiyar     // TODO: Need to figure out dynamic way to restrict patch (Set Sensor
1000413961deSRichard Marian Thomaiyar     // override) based on another d-bus announcement to be more generic.
1001413961deSRichard Marian Thomaiyar     if (params.size() != 1)
1002413961deSRichard Marian Thomaiyar     {
1003413961deSRichard Marian Thomaiyar         messages::internalError(res);
1004413961deSRichard Marian Thomaiyar         res.end();
1005413961deSRichard Marian Thomaiyar         return;
1006413961deSRichard Marian Thomaiyar     }
1007f65af9e8SRichard Marian Thomaiyar 
1008f65af9e8SRichard Marian Thomaiyar     std::unordered_map<std::string, std::vector<nlohmann::json>> allCollections;
1009f65af9e8SRichard Marian Thomaiyar     std::optional<std::vector<nlohmann::json>> temperatureCollections;
1010f65af9e8SRichard Marian Thomaiyar     std::optional<std::vector<nlohmann::json>> fanCollections;
1011f65af9e8SRichard Marian Thomaiyar     std::vector<nlohmann::json> voltageCollections;
1012f65af9e8SRichard Marian Thomaiyar     BMCWEB_LOG_INFO << "setSensorOverride for subNode" << chassisSubNode
1013f65af9e8SRichard Marian Thomaiyar                     << "\n";
1014f65af9e8SRichard Marian Thomaiyar 
1015413961deSRichard Marian Thomaiyar     if (chassisSubNode == "Thermal")
1016413961deSRichard Marian Thomaiyar     {
1017f65af9e8SRichard Marian Thomaiyar         if (!json_util::readJson(req, res, "Temperatures",
1018f65af9e8SRichard Marian Thomaiyar                                  temperatureCollections, "Fans",
1019f65af9e8SRichard Marian Thomaiyar                                  fanCollections))
1020f65af9e8SRichard Marian Thomaiyar         {
1021f65af9e8SRichard Marian Thomaiyar             return;
1022f65af9e8SRichard Marian Thomaiyar         }
1023f65af9e8SRichard Marian Thomaiyar         if (!temperatureCollections && !fanCollections)
1024f65af9e8SRichard Marian Thomaiyar         {
1025f65af9e8SRichard Marian Thomaiyar             messages::resourceNotFound(res, "Thermal",
1026f65af9e8SRichard Marian Thomaiyar                                        "Temperatures / Voltages");
1027f65af9e8SRichard Marian Thomaiyar             res.end();
1028f65af9e8SRichard Marian Thomaiyar             return;
1029f65af9e8SRichard Marian Thomaiyar         }
1030f65af9e8SRichard Marian Thomaiyar         if (temperatureCollections)
1031f65af9e8SRichard Marian Thomaiyar         {
1032f65af9e8SRichard Marian Thomaiyar             allCollections.emplace("Temperatures",
1033f65af9e8SRichard Marian Thomaiyar                                    *std::move(temperatureCollections));
1034f65af9e8SRichard Marian Thomaiyar         }
1035f65af9e8SRichard Marian Thomaiyar         if (fanCollections)
1036f65af9e8SRichard Marian Thomaiyar         {
1037f65af9e8SRichard Marian Thomaiyar             allCollections.emplace("Fans", *std::move(fanCollections));
1038f65af9e8SRichard Marian Thomaiyar         }
1039413961deSRichard Marian Thomaiyar     }
1040413961deSRichard Marian Thomaiyar     else if (chassisSubNode == "Power")
1041413961deSRichard Marian Thomaiyar     {
1042f65af9e8SRichard Marian Thomaiyar         if (!json_util::readJson(req, res, "Voltages", voltageCollections))
1043f65af9e8SRichard Marian Thomaiyar         {
1044f65af9e8SRichard Marian Thomaiyar             return;
1045f65af9e8SRichard Marian Thomaiyar         }
1046f65af9e8SRichard Marian Thomaiyar         allCollections.emplace("Voltages", std::move(voltageCollections));
1047413961deSRichard Marian Thomaiyar     }
1048413961deSRichard Marian Thomaiyar     else
1049413961deSRichard Marian Thomaiyar     {
1050413961deSRichard Marian Thomaiyar         res.result(boost::beast::http::status::not_found);
1051413961deSRichard Marian Thomaiyar         res.end();
1052413961deSRichard Marian Thomaiyar         return;
1053413961deSRichard Marian Thomaiyar     }
1054413961deSRichard Marian Thomaiyar 
1055f65af9e8SRichard Marian Thomaiyar     const char* propertyValueName;
1056f65af9e8SRichard Marian Thomaiyar     std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
1057413961deSRichard Marian Thomaiyar     std::string memberId;
1058413961deSRichard Marian Thomaiyar     double value;
1059f65af9e8SRichard Marian Thomaiyar     for (auto& collectionItems : allCollections)
1060f65af9e8SRichard Marian Thomaiyar     {
1061f65af9e8SRichard Marian Thomaiyar         if (collectionItems.first == "Temperatures")
1062f65af9e8SRichard Marian Thomaiyar         {
1063f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingCelsius";
1064f65af9e8SRichard Marian Thomaiyar         }
1065f65af9e8SRichard Marian Thomaiyar         else if (collectionItems.first == "Fans")
1066f65af9e8SRichard Marian Thomaiyar         {
1067f65af9e8SRichard Marian Thomaiyar             propertyValueName = "Reading";
1068f65af9e8SRichard Marian Thomaiyar         }
1069f65af9e8SRichard Marian Thomaiyar         else
1070f65af9e8SRichard Marian Thomaiyar         {
1071f65af9e8SRichard Marian Thomaiyar             propertyValueName = "ReadingVolts";
1072f65af9e8SRichard Marian Thomaiyar         }
1073f65af9e8SRichard Marian Thomaiyar         for (auto& item : collectionItems.second)
1074f65af9e8SRichard Marian Thomaiyar         {
1075f65af9e8SRichard Marian Thomaiyar             if (!json_util::readJson(item, res, "MemberId", memberId,
1076413961deSRichard Marian Thomaiyar                                      propertyValueName, value))
1077413961deSRichard Marian Thomaiyar             {
1078413961deSRichard Marian Thomaiyar                 return;
1079413961deSRichard Marian Thomaiyar             }
1080f65af9e8SRichard Marian Thomaiyar             overrideMap.emplace(memberId,
1081f65af9e8SRichard Marian Thomaiyar                                 std::make_pair(value, collectionItems.first));
1082f65af9e8SRichard Marian Thomaiyar         }
1083f65af9e8SRichard Marian Thomaiyar     }
1084413961deSRichard Marian Thomaiyar     const std::string& chassisName = params[0];
1085413961deSRichard Marian Thomaiyar     auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
1086413961deSRichard Marian Thomaiyar         res, chassisName, typeList, chassisSubNode);
1087413961deSRichard Marian Thomaiyar     // first check for valid chassis id & sensor in requested chassis.
1088f65af9e8SRichard Marian Thomaiyar     auto getChassisSensorListCb = [sensorAsyncResp, overrideMap](
1089f65af9e8SRichard Marian Thomaiyar                                       const boost::container::flat_set<
1090f65af9e8SRichard Marian Thomaiyar                                           std::string>& sensorLists) {
1091f65af9e8SRichard Marian Thomaiyar         boost::container::flat_set<std::string> sensorNames;
1092f65af9e8SRichard Marian Thomaiyar         for (const auto& item : overrideMap)
1093413961deSRichard Marian Thomaiyar         {
1094f65af9e8SRichard Marian Thomaiyar             const auto& sensor = item.first;
1095f65af9e8SRichard Marian Thomaiyar             if (sensorLists.find(item.first) == sensorLists.end())
1096f65af9e8SRichard Marian Thomaiyar             {
1097f65af9e8SRichard Marian Thomaiyar                 BMCWEB_LOG_INFO << "Unable to find memberId " << item.first;
1098413961deSRichard Marian Thomaiyar                 messages::resourceNotFound(sensorAsyncResp->res,
1099f65af9e8SRichard Marian Thomaiyar                                            item.second.second, item.first);
1100413961deSRichard Marian Thomaiyar                 return;
1101413961deSRichard Marian Thomaiyar             }
1102f65af9e8SRichard Marian Thomaiyar             sensorNames.emplace(sensor);
1103f65af9e8SRichard Marian Thomaiyar         }
1104413961deSRichard Marian Thomaiyar         // Get the connection to which the memberId belongs
1105413961deSRichard Marian Thomaiyar         auto getObjectsWithConnectionCb =
1106f65af9e8SRichard Marian Thomaiyar             [sensorAsyncResp, overrideMap](
1107413961deSRichard Marian Thomaiyar                 const boost::container::flat_set<std::string>& connections,
1108413961deSRichard Marian Thomaiyar                 const std::set<std::pair<std::string, std::string>>&
1109413961deSRichard Marian Thomaiyar                     objectsWithConnection) {
1110f65af9e8SRichard Marian Thomaiyar                 if (objectsWithConnection.size() != overrideMap.size())
1111413961deSRichard Marian Thomaiyar                 {
1112413961deSRichard Marian Thomaiyar                     BMCWEB_LOG_INFO
1113f65af9e8SRichard Marian Thomaiyar                         << "Unable to find all objects with proper connection "
1114f65af9e8SRichard Marian Thomaiyar                         << objectsWithConnection.size() << " requested "
1115f65af9e8SRichard Marian Thomaiyar                         << overrideMap.size() << "\n";
1116413961deSRichard Marian Thomaiyar                     messages::resourceNotFound(
1117413961deSRichard Marian Thomaiyar                         sensorAsyncResp->res,
1118413961deSRichard Marian Thomaiyar                         sensorAsyncResp->chassisSubNode == "Thermal"
1119413961deSRichard Marian Thomaiyar                             ? "Temperatures"
1120413961deSRichard Marian Thomaiyar                             : "Voltages",
1121f65af9e8SRichard Marian Thomaiyar                         "Count");
1122f65af9e8SRichard Marian Thomaiyar                     return;
1123f65af9e8SRichard Marian Thomaiyar                 }
1124f65af9e8SRichard Marian Thomaiyar                 for (const auto& item : objectsWithConnection)
1125f65af9e8SRichard Marian Thomaiyar                 {
1126f65af9e8SRichard Marian Thomaiyar 
1127f65af9e8SRichard Marian Thomaiyar                     auto lastPos = item.first.rfind('/');
1128f65af9e8SRichard Marian Thomaiyar                     if (lastPos == std::string::npos)
1129f65af9e8SRichard Marian Thomaiyar                     {
1130f65af9e8SRichard Marian Thomaiyar                         messages::internalError(sensorAsyncResp->res);
1131f65af9e8SRichard Marian Thomaiyar                         return;
1132f65af9e8SRichard Marian Thomaiyar                     }
1133f65af9e8SRichard Marian Thomaiyar                     std::string sensorName = item.first.substr(lastPos + 1);
1134f65af9e8SRichard Marian Thomaiyar 
1135f65af9e8SRichard Marian Thomaiyar                     const auto& iterator = overrideMap.find(sensorName);
1136f65af9e8SRichard Marian Thomaiyar                     if (iterator == overrideMap.end())
1137f65af9e8SRichard Marian Thomaiyar                     {
1138f65af9e8SRichard Marian Thomaiyar                         BMCWEB_LOG_INFO << "Unable to find sensor object"
1139f65af9e8SRichard Marian Thomaiyar                                         << item.first << "\n";
1140f65af9e8SRichard Marian Thomaiyar                         messages::internalError(sensorAsyncResp->res);
1141413961deSRichard Marian Thomaiyar                         return;
1142413961deSRichard Marian Thomaiyar                     }
1143413961deSRichard Marian Thomaiyar                     crow::connections::systemBus->async_method_call(
1144f65af9e8SRichard Marian Thomaiyar                         [sensorAsyncResp](const boost::system::error_code ec) {
1145413961deSRichard Marian Thomaiyar                             if (ec)
1146413961deSRichard Marian Thomaiyar                             {
1147413961deSRichard Marian Thomaiyar                                 BMCWEB_LOG_DEBUG
1148f65af9e8SRichard Marian Thomaiyar                                     << "setOverrideValueStatus DBUS error: "
1149413961deSRichard Marian Thomaiyar                                     << ec;
1150413961deSRichard Marian Thomaiyar                                 messages::internalError(sensorAsyncResp->res);
1151413961deSRichard Marian Thomaiyar                                 return;
1152413961deSRichard Marian Thomaiyar                             }
1153413961deSRichard Marian Thomaiyar                         },
1154f65af9e8SRichard Marian Thomaiyar                         item.second, item.first,
1155413961deSRichard Marian Thomaiyar                         "org.freedesktop.DBus.Properties", "Set",
1156413961deSRichard Marian Thomaiyar                         "xyz.openbmc_project.Sensor.Value", "Value",
1157f65af9e8SRichard Marian Thomaiyar                         sdbusplus::message::variant<double>(
1158f65af9e8SRichard Marian Thomaiyar                             iterator->second.first));
1159f65af9e8SRichard Marian Thomaiyar                 }
1160413961deSRichard Marian Thomaiyar             };
1161413961deSRichard Marian Thomaiyar         // Get object with connection for the given sensor name
1162413961deSRichard Marian Thomaiyar         getObjectsWithConnection(sensorAsyncResp, sensorNames,
1163413961deSRichard Marian Thomaiyar                                  std::move(getObjectsWithConnectionCb));
1164413961deSRichard Marian Thomaiyar     };
1165413961deSRichard Marian Thomaiyar     // get full sensor list for the given chassisId and cross verify the sensor.
1166413961deSRichard Marian Thomaiyar     getChassis(sensorAsyncResp, std::move(getChassisSensorListCb));
1167413961deSRichard Marian Thomaiyar }
1168413961deSRichard Marian Thomaiyar 
116908777fb0SLewanczyk, Dawid } // namespace redfish
1170