xref: /openbmc/bmcweb/features/redfish/lib/sensors.hpp (revision 1abe55ef9844afcddcab9d862ae06118f3a2390c)
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>
19*1abe55efSEd 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>
24*1abe55efSEd Tanous #include <dbus_singleton.hpp>
2508777fb0SLewanczyk, Dawid 
26*1abe55efSEd Tanous namespace redfish
27*1abe55efSEd Tanous {
2808777fb0SLewanczyk, Dawid 
29d76323e5SEd Tanous constexpr const char* dbusSensorPrefix = "/xyz/openbmc_project/sensors/";
3008777fb0SLewanczyk, Dawid 
3108777fb0SLewanczyk, Dawid using GetSubTreeType = std::vector<
3208777fb0SLewanczyk, Dawid     std::pair<std::string,
3308777fb0SLewanczyk, Dawid               std::vector<std::pair<std::string, std::vector<std::string>>>>>;
3408777fb0SLewanczyk, Dawid 
35aa2e59c1SEd Tanous using SensorVariant = sdbusplus::message::variant<int64_t, double>;
36aa2e59c1SEd Tanous 
3708777fb0SLewanczyk, Dawid using ManagedObjectsVectorType = std::vector<std::pair<
38aa2e59c1SEd Tanous     sdbusplus::message::object_path,
3908777fb0SLewanczyk, Dawid     boost::container::flat_map<
40aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>>>;
4108777fb0SLewanczyk, Dawid 
4208777fb0SLewanczyk, Dawid /**
43588c3f0dSKowalski, Kamil  * SensorsAsyncResp
4408777fb0SLewanczyk, Dawid  * Gathers data needed for response processing after async calls are done
4508777fb0SLewanczyk, Dawid  */
46*1abe55efSEd Tanous class SensorsAsyncResp
47*1abe55efSEd Tanous {
4808777fb0SLewanczyk, Dawid   public:
4955c7b7a2SEd Tanous     SensorsAsyncResp(crow::Response& response, const std::string& chassisId,
50*1abe55efSEd Tanous                      const std::initializer_list<const char*> types) :
51*1abe55efSEd Tanous         res(response),
52*1abe55efSEd Tanous         chassisId(chassisId), types(types)
53*1abe55efSEd Tanous     {
5455c7b7a2SEd Tanous         res.jsonValue["@odata.id"] =
5508777fb0SLewanczyk, Dawid             "/redfish/v1/Chassis/" + chassisId + "/Thermal";
5608777fb0SLewanczyk, Dawid     }
5708777fb0SLewanczyk, Dawid 
58*1abe55efSEd Tanous     ~SensorsAsyncResp()
59*1abe55efSEd Tanous     {
60*1abe55efSEd Tanous         if (res.result() == boost::beast::http::status::internal_server_error)
61*1abe55efSEd Tanous         {
62*1abe55efSEd Tanous             // Reset the json object to clear out any data that made it in
63*1abe55efSEd Tanous             // before the error happened todo(ed) handle error condition with
64*1abe55efSEd Tanous             // proper code
6555c7b7a2SEd Tanous             res.jsonValue = nlohmann::json::object();
6608777fb0SLewanczyk, Dawid         }
6708777fb0SLewanczyk, Dawid         res.end();
6808777fb0SLewanczyk, Dawid     }
69588c3f0dSKowalski, Kamil 
70*1abe55efSEd Tanous     void setErrorStatus()
71*1abe55efSEd Tanous     {
72e0d918bcSEd Tanous         res.result(boost::beast::http::status::internal_server_error);
7308777fb0SLewanczyk, Dawid     }
7408777fb0SLewanczyk, Dawid 
7555c7b7a2SEd Tanous     crow::Response& res;
76588c3f0dSKowalski, Kamil     std::string chassisId{};
7708777fb0SLewanczyk, Dawid     const std::vector<const char*> types;
7808777fb0SLewanczyk, Dawid };
7908777fb0SLewanczyk, Dawid 
8008777fb0SLewanczyk, Dawid /**
8108777fb0SLewanczyk, Dawid  * @brief Creates connections necessary for chassis sensors
82588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp Pointer to object holding response data
8308777fb0SLewanczyk, Dawid  * @param sensorNames Sensors retrieved from chassis
8408777fb0SLewanczyk, Dawid  * @param callback Callback for processing gathered connections
8508777fb0SLewanczyk, Dawid  */
8608777fb0SLewanczyk, Dawid template <typename Callback>
87588c3f0dSKowalski, Kamil void getConnections(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
8808777fb0SLewanczyk, Dawid                     const boost::container::flat_set<std::string>& sensorNames,
89*1abe55efSEd Tanous                     Callback&& callback)
90*1abe55efSEd Tanous {
9155c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getConnections enter";
9203b5bae3SJames Feist     const std::string path = "/xyz/openbmc_project/sensors";
9308777fb0SLewanczyk, Dawid     const std::array<std::string, 1> interfaces = {
9408777fb0SLewanczyk, Dawid         "xyz.openbmc_project.Sensor.Value"};
9508777fb0SLewanczyk, Dawid 
9608777fb0SLewanczyk, Dawid     // Response handler for parsing objects subtree
97*1abe55efSEd Tanous     auto respHandler = [callback{std::move(callback)}, SensorsAsyncResp,
98*1abe55efSEd Tanous                         sensorNames](const boost::system::error_code ec,
99*1abe55efSEd Tanous                                      const GetSubTreeType& subtree) {
10055c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getConnections resp_handler enter";
101*1abe55efSEd Tanous         if (ec)
102*1abe55efSEd Tanous         {
103588c3f0dSKowalski, Kamil             SensorsAsyncResp->setErrorStatus();
104*1abe55efSEd Tanous             BMCWEB_LOG_ERROR << "getConnections resp_handler: Dbus error "
105*1abe55efSEd Tanous                              << ec;
10608777fb0SLewanczyk, Dawid             return;
10708777fb0SLewanczyk, Dawid         }
10808777fb0SLewanczyk, Dawid 
10955c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
11008777fb0SLewanczyk, Dawid 
11108777fb0SLewanczyk, Dawid         // Make unique list of connections only for requested sensor types and
11208777fb0SLewanczyk, Dawid         // found in the chassis
11308777fb0SLewanczyk, Dawid         boost::container::flat_set<std::string> connections;
114*1abe55efSEd Tanous         // Intrinsic to avoid malloc.  Most systems will have < 8 sensor
115*1abe55efSEd Tanous         // producers
11608777fb0SLewanczyk, Dawid         connections.reserve(8);
11708777fb0SLewanczyk, Dawid 
11855c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames.size();
119*1abe55efSEd Tanous         for (const std::string& tsensor : sensorNames)
120*1abe55efSEd Tanous         {
12155c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor;
12208777fb0SLewanczyk, Dawid         }
12308777fb0SLewanczyk, Dawid 
12408777fb0SLewanczyk, Dawid         for (const std::pair<
12508777fb0SLewanczyk, Dawid                  std::string,
12608777fb0SLewanczyk, Dawid                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
127*1abe55efSEd Tanous                  object : subtree)
128*1abe55efSEd Tanous         {
129*1abe55efSEd Tanous             for (const char* type : SensorsAsyncResp->types)
130*1abe55efSEd Tanous             {
131*1abe55efSEd Tanous                 if (boost::starts_with(object.first, type))
132*1abe55efSEd Tanous                 {
13308777fb0SLewanczyk, Dawid                     auto lastPos = object.first.rfind('/');
134*1abe55efSEd Tanous                     if (lastPos != std::string::npos)
135*1abe55efSEd Tanous                     {
136*1abe55efSEd Tanous                         std::string sensorName =
137*1abe55efSEd Tanous                             object.first.substr(lastPos + 1);
13808777fb0SLewanczyk, Dawid 
139*1abe55efSEd Tanous                         if (sensorNames.find(sensorName) != sensorNames.end())
140*1abe55efSEd Tanous                         {
14155c7b7a2SEd Tanous                             // For each Connection name
142*1abe55efSEd Tanous                             for (const std::pair<std::string,
143*1abe55efSEd Tanous                                                  std::vector<std::string>>&
144*1abe55efSEd Tanous                                      objData : object.second)
145*1abe55efSEd Tanous                             {
146*1abe55efSEd Tanous                                 BMCWEB_LOG_DEBUG << "Adding connection: "
147*1abe55efSEd Tanous                                                  << objData.first;
14808777fb0SLewanczyk, Dawid                                 connections.insert(objData.first);
14908777fb0SLewanczyk, Dawid                             }
15008777fb0SLewanczyk, Dawid                         }
15108777fb0SLewanczyk, Dawid                     }
15208777fb0SLewanczyk, Dawid                     break;
15308777fb0SLewanczyk, Dawid                 }
15408777fb0SLewanczyk, Dawid             }
15508777fb0SLewanczyk, Dawid         }
15655c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections";
15708777fb0SLewanczyk, Dawid         callback(std::move(connections));
15855c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getConnections resp_handler exit";
15908777fb0SLewanczyk, Dawid     };
16008777fb0SLewanczyk, Dawid 
16108777fb0SLewanczyk, Dawid     // Make call to ObjectMapper to find all sensors objects
16255c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
16355c7b7a2SEd Tanous         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
164*1abe55efSEd Tanous         "/xyz/openbmc_project/object_mapper",
165*1abe55efSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 2, interfaces);
16655c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getConnections exit";
16708777fb0SLewanczyk, Dawid }
16808777fb0SLewanczyk, Dawid 
16908777fb0SLewanczyk, Dawid /**
17008777fb0SLewanczyk, Dawid  * @brief Retrieves requested chassis sensors and redundancy data from DBus .
171588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
17208777fb0SLewanczyk, Dawid  * @param callback  Callback for next step in gathered sensor processing
17308777fb0SLewanczyk, Dawid  */
17408777fb0SLewanczyk, Dawid template <typename Callback>
175588c3f0dSKowalski, Kamil void getChassis(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
176*1abe55efSEd Tanous                 Callback&& callback)
177*1abe55efSEd Tanous {
17855c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis enter";
17908777fb0SLewanczyk, Dawid     // Process response from EntityManager and extract chassis data
180*1abe55efSEd Tanous     auto respHandler = [callback{std::move(callback)},
181*1abe55efSEd Tanous                         SensorsAsyncResp](const boost::system::error_code ec,
182*1abe55efSEd Tanous                                           ManagedObjectsVectorType& resp) {
18355c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassis respHandler enter";
184*1abe55efSEd Tanous         if (ec)
185*1abe55efSEd Tanous         {
18655c7b7a2SEd Tanous             BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec;
187588c3f0dSKowalski, Kamil             SensorsAsyncResp->setErrorStatus();
18808777fb0SLewanczyk, Dawid             return;
18908777fb0SLewanczyk, Dawid         }
19008777fb0SLewanczyk, Dawid         boost::container::flat_set<std::string> sensorNames;
19108777fb0SLewanczyk, Dawid 
192588c3f0dSKowalski, Kamil         //   SensorsAsyncResp->chassisId
193daf36e2eSEd Tanous         bool foundChassis = false;
194daf36e2eSEd Tanous         std::vector<std::string> split;
195daf36e2eSEd Tanous         // Reserve space for
196daf36e2eSEd Tanous         // /xyz/openbmc_project/inventory/<name>/<subname> + 3 subnames
197daf36e2eSEd Tanous         split.reserve(8);
198daf36e2eSEd Tanous 
199*1abe55efSEd Tanous         for (const auto& objDictEntry : resp)
200*1abe55efSEd Tanous         {
201daf36e2eSEd Tanous             const std::string& objectPath =
202daf36e2eSEd Tanous                 static_cast<const std::string&>(objDictEntry.first);
203daf36e2eSEd Tanous             boost::algorithm::split(split, objectPath, boost::is_any_of("/"));
204*1abe55efSEd Tanous             if (split.size() < 2)
205*1abe55efSEd Tanous             {
206*1abe55efSEd Tanous                 BMCWEB_LOG_ERROR << "Got path that isn't long enough "
207*1abe55efSEd Tanous                                  << objectPath;
208daf36e2eSEd Tanous                 split.clear();
209daf36e2eSEd Tanous                 continue;
210daf36e2eSEd Tanous             }
211daf36e2eSEd Tanous             const std::string& sensorName = split.end()[-1];
212daf36e2eSEd Tanous             const std::string& chassisName = split.end()[-2];
213daf36e2eSEd Tanous 
214*1abe55efSEd Tanous             if (chassisName != SensorsAsyncResp->chassisId)
215*1abe55efSEd Tanous             {
216daf36e2eSEd Tanous                 split.clear();
217daf36e2eSEd Tanous                 continue;
218daf36e2eSEd Tanous             }
21955c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "New sensor: " << sensorName;
220daf36e2eSEd Tanous             foundChassis = true;
22108777fb0SLewanczyk, Dawid             sensorNames.emplace(sensorName);
222daf36e2eSEd Tanous             split.clear();
22308777fb0SLewanczyk, Dawid         };
22455c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << sensorNames.size() << " Sensor names";
22508777fb0SLewanczyk, Dawid 
226*1abe55efSEd Tanous         if (!foundChassis)
227*1abe55efSEd Tanous         {
22855c7b7a2SEd Tanous             BMCWEB_LOG_INFO << "Unable to find chassis named "
229588c3f0dSKowalski, Kamil                             << SensorsAsyncResp->chassisId;
230588c3f0dSKowalski, Kamil             SensorsAsyncResp->res.result(boost::beast::http::status::not_found);
231*1abe55efSEd Tanous         }
232*1abe55efSEd Tanous         else
233*1abe55efSEd Tanous         {
23408777fb0SLewanczyk, Dawid             callback(sensorNames);
23508777fb0SLewanczyk, Dawid         }
23655c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassis respHandler exit";
23708777fb0SLewanczyk, Dawid     };
23808777fb0SLewanczyk, Dawid 
23908777fb0SLewanczyk, Dawid     // Make call to EntityManager to find all chassis objects
24055c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
24155c7b7a2SEd Tanous         respHandler, "xyz.openbmc_project.EntityManager", "/",
2427885954aSLewanczyk, Dawid         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
24355c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis exit";
24408777fb0SLewanczyk, Dawid }
24508777fb0SLewanczyk, Dawid 
24608777fb0SLewanczyk, Dawid /**
24708777fb0SLewanczyk, Dawid  * @brief Builds a json sensor representation of a sensor.
24808777fb0SLewanczyk, Dawid  * @param sensorName  The name of the sensor to be built
249274fad5aSGunnar Mills  * @param sensorType  The type (temperature, fan_tach, etc) of the sensor to
25008777fb0SLewanczyk, Dawid  * build
25108777fb0SLewanczyk, Dawid  * @param interfacesDict  A dictionary of the interfaces and properties of said
25208777fb0SLewanczyk, Dawid  * interfaces to be built from
25308777fb0SLewanczyk, Dawid  * @param sensor_json  The json object to fill
25408777fb0SLewanczyk, Dawid  */
25508777fb0SLewanczyk, Dawid void objectInterfacesToJson(
25608777fb0SLewanczyk, Dawid     const std::string& sensorName, const std::string& sensorType,
25708777fb0SLewanczyk, Dawid     const boost::container::flat_map<
258aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>&
25908777fb0SLewanczyk, Dawid         interfacesDict,
260*1abe55efSEd Tanous     nlohmann::json& sensor_json)
261*1abe55efSEd Tanous {
26208777fb0SLewanczyk, Dawid     // We need a value interface before we can do anything with it
26355c7b7a2SEd Tanous     auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
264*1abe55efSEd Tanous     if (valueIt == interfacesDict.end())
265*1abe55efSEd Tanous     {
26655c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface";
26708777fb0SLewanczyk, Dawid         return;
26808777fb0SLewanczyk, Dawid     }
26908777fb0SLewanczyk, Dawid 
27008777fb0SLewanczyk, Dawid     // Assume values exist as is (10^0 == 1) if no scale exists
27108777fb0SLewanczyk, Dawid     int64_t scaleMultiplier = 0;
27208777fb0SLewanczyk, Dawid 
27355c7b7a2SEd Tanous     auto scaleIt = valueIt->second.find("Scale");
27408777fb0SLewanczyk, Dawid     // If a scale exists, pull value as int64, and use the scaling.
275*1abe55efSEd Tanous     if (scaleIt != valueIt->second.end())
276*1abe55efSEd Tanous     {
277*1abe55efSEd Tanous         const int64_t* int64Value =
278*1abe55efSEd Tanous             mapbox::getPtr<const int64_t>(scaleIt->second);
279*1abe55efSEd Tanous         if (int64Value != nullptr)
280*1abe55efSEd Tanous         {
28108777fb0SLewanczyk, Dawid             scaleMultiplier = *int64Value;
28208777fb0SLewanczyk, Dawid         }
28308777fb0SLewanczyk, Dawid     }
28408777fb0SLewanczyk, Dawid 
28508777fb0SLewanczyk, Dawid     sensor_json["MemberId"] = sensorName;
28608777fb0SLewanczyk, Dawid     sensor_json["Name"] = sensorName;
28708777fb0SLewanczyk, Dawid     sensor_json["Status"]["State"] = "Enabled";
28808777fb0SLewanczyk, Dawid     sensor_json["Status"]["Health"] = "OK";
28908777fb0SLewanczyk, Dawid 
29008777fb0SLewanczyk, Dawid     // Parameter to set to override the type we get from dbus, and force it to
29108777fb0SLewanczyk, Dawid     // int, regardless of what is available.  This is used for schemas like fan,
29208777fb0SLewanczyk, Dawid     // that require integers, not floats.
29308777fb0SLewanczyk, Dawid     bool forceToInt = false;
29408777fb0SLewanczyk, Dawid 
29508777fb0SLewanczyk, Dawid     const char* unit = "Reading";
296*1abe55efSEd Tanous     if (sensorType == "temperature")
297*1abe55efSEd Tanous     {
29808777fb0SLewanczyk, Dawid         unit = "ReadingCelsius";
2997885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature";
30008777fb0SLewanczyk, Dawid         // TODO(ed) Documentation says that path should be type fan_tach,
30108777fb0SLewanczyk, Dawid         // implementation seems to implement fan
302*1abe55efSEd Tanous     }
303*1abe55efSEd Tanous     else if (sensorType == "fan" || sensorType == "fan_tach")
304*1abe55efSEd Tanous     {
30508777fb0SLewanczyk, Dawid         unit = "Reading";
30608777fb0SLewanczyk, Dawid         sensor_json["ReadingUnits"] = "RPM";
3077885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
30808777fb0SLewanczyk, Dawid         forceToInt = true;
309*1abe55efSEd Tanous     }
310*1abe55efSEd Tanous     else if (sensorType == "voltage")
311*1abe55efSEd Tanous     {
31208777fb0SLewanczyk, Dawid         unit = "ReadingVolts";
3137885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage";
314*1abe55efSEd Tanous     }
315*1abe55efSEd Tanous     else
316*1abe55efSEd Tanous     {
31755c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
31808777fb0SLewanczyk, Dawid         return;
31908777fb0SLewanczyk, Dawid     }
32008777fb0SLewanczyk, Dawid     // Map of dbus interface name, dbus property name and redfish property_name
32108777fb0SLewanczyk, Dawid     std::vector<std::tuple<const char*, const char*, const char*>> properties;
32208777fb0SLewanczyk, Dawid     properties.reserve(7);
32308777fb0SLewanczyk, Dawid 
32408777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
32508777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
32608777fb0SLewanczyk, Dawid                             "WarningHigh", "UpperThresholdNonCritical");
32708777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
32808777fb0SLewanczyk, Dawid                             "WarningLow", "LowerThresholdNonCritical");
32908777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
33008777fb0SLewanczyk, Dawid                             "CriticalHigh", "UpperThresholdCritical");
33108777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
33208777fb0SLewanczyk, Dawid                             "CriticalLow", "LowerThresholdCritical");
33308777fb0SLewanczyk, Dawid 
334*1abe55efSEd Tanous     if (sensorType == "temperature")
335*1abe55efSEd Tanous     {
33608777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
33708777fb0SLewanczyk, Dawid                                 "MinReadingRangeTemp");
33808777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
33908777fb0SLewanczyk, Dawid                                 "MaxReadingRangeTemp");
340*1abe55efSEd Tanous     }
341*1abe55efSEd Tanous     else
342*1abe55efSEd Tanous     {
34308777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
34408777fb0SLewanczyk, Dawid                                 "MinReadingRange");
34508777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
34608777fb0SLewanczyk, Dawid                                 "MaxReadingRange");
34708777fb0SLewanczyk, Dawid     }
34808777fb0SLewanczyk, Dawid 
34908777fb0SLewanczyk, Dawid     for (const std::tuple<const char*, const char*, const char*>& p :
350*1abe55efSEd Tanous          properties)
351*1abe55efSEd Tanous     {
35208777fb0SLewanczyk, Dawid         auto interfaceProperties = interfacesDict.find(std::get<0>(p));
353*1abe55efSEd Tanous         if (interfaceProperties != interfacesDict.end())
354*1abe55efSEd Tanous         {
35555c7b7a2SEd Tanous             auto valueIt = interfaceProperties->second.find(std::get<1>(p));
356*1abe55efSEd Tanous             if (valueIt != interfaceProperties->second.end())
357*1abe55efSEd Tanous             {
35855c7b7a2SEd Tanous                 const SensorVariant& valueVariant = valueIt->second;
35955c7b7a2SEd Tanous                 nlohmann::json& valueIt = sensor_json[std::get<2>(p)];
360aa2e59c1SEd Tanous 
36108777fb0SLewanczyk, Dawid                 // Attempt to pull the int64 directly
362*1abe55efSEd Tanous                 const int64_t* int64Value =
363*1abe55efSEd Tanous                     mapbox::getPtr<const int64_t>(valueVariant);
36408777fb0SLewanczyk, Dawid 
365*1abe55efSEd Tanous                 if (int64Value != nullptr)
366*1abe55efSEd Tanous                 {
367*1abe55efSEd Tanous                     if (forceToInt || scaleMultiplier >= 0)
368*1abe55efSEd Tanous                     {
36955c7b7a2SEd Tanous                         valueIt = *int64Value * std::pow(10, scaleMultiplier);
370*1abe55efSEd Tanous                     }
371*1abe55efSEd Tanous                     else
372*1abe55efSEd Tanous                     {
373*1abe55efSEd Tanous                         valueIt =
374*1abe55efSEd Tanous                             *int64Value *
37508777fb0SLewanczyk, Dawid                             std::pow(10, static_cast<double>(scaleMultiplier));
37608777fb0SLewanczyk, Dawid                     }
37708777fb0SLewanczyk, Dawid                 }
37808777fb0SLewanczyk, Dawid                 // Attempt to pull the float directly
379*1abe55efSEd Tanous                 const double* doubleValue =
380*1abe55efSEd Tanous                     mapbox::getPtr<const double>(valueVariant);
38108777fb0SLewanczyk, Dawid 
382*1abe55efSEd Tanous                 if (doubleValue != nullptr)
383*1abe55efSEd Tanous                 {
384*1abe55efSEd Tanous                     if (!forceToInt)
385*1abe55efSEd Tanous                     {
386*1abe55efSEd Tanous                         valueIt =
387*1abe55efSEd Tanous                             *doubleValue *
38808777fb0SLewanczyk, Dawid                             std::pow(10, static_cast<double>(scaleMultiplier));
389*1abe55efSEd Tanous                     }
390*1abe55efSEd Tanous                     else
391*1abe55efSEd Tanous                     {
392*1abe55efSEd Tanous                         valueIt = static_cast<int64_t>(
393*1abe55efSEd Tanous                             *doubleValue * std::pow(10, scaleMultiplier));
39408777fb0SLewanczyk, Dawid                     }
39508777fb0SLewanczyk, Dawid                 }
39608777fb0SLewanczyk, Dawid             }
39708777fb0SLewanczyk, Dawid         }
39808777fb0SLewanczyk, Dawid     }
39955c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
40008777fb0SLewanczyk, Dawid }
40108777fb0SLewanczyk, Dawid 
40208777fb0SLewanczyk, Dawid /**
40308777fb0SLewanczyk, Dawid  * @brief Entry point for retrieving sensors data related to requested
40408777fb0SLewanczyk, Dawid  *        chassis.
405588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
40608777fb0SLewanczyk, Dawid  */
407*1abe55efSEd Tanous void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
408*1abe55efSEd Tanous {
40955c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisData enter";
410588c3f0dSKowalski, Kamil     auto getChassisCb = [&, SensorsAsyncResp](
411588c3f0dSKowalski, Kamil                             boost::container::flat_set<std::string>&
41208777fb0SLewanczyk, Dawid                                 sensorNames) {
41355c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassisCb enter";
414588c3f0dSKowalski, Kamil         auto getConnectionCb =
415588c3f0dSKowalski, Kamil             [&, SensorsAsyncResp, sensorNames](
416588c3f0dSKowalski, Kamil                 const boost::container::flat_set<std::string>& connections) {
41755c7b7a2SEd Tanous                 BMCWEB_LOG_DEBUG << "getConnectionCb enter";
41808777fb0SLewanczyk, Dawid                 // Get managed objects from all services exposing sensors
419*1abe55efSEd Tanous                 for (const std::string& connection : connections)
420*1abe55efSEd Tanous                 {
42108777fb0SLewanczyk, Dawid                     // Response handler to process managed objects
422*1abe55efSEd Tanous                     auto getManagedObjectsCb =
423*1abe55efSEd Tanous                         [&, SensorsAsyncResp,
424*1abe55efSEd Tanous                          sensorNames](const boost::system::error_code ec,
42508777fb0SLewanczyk, Dawid                                       ManagedObjectsVectorType& resp) {
42655c7b7a2SEd Tanous                             BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
427*1abe55efSEd Tanous                             if (ec)
428*1abe55efSEd Tanous                             {
429*1abe55efSEd Tanous                                 BMCWEB_LOG_ERROR
430*1abe55efSEd Tanous                                     << "getManagedObjectsCb DBUS error: " << ec;
4317885954aSLewanczyk, Dawid                                 SensorsAsyncResp->setErrorStatus();
4327885954aSLewanczyk, Dawid                                 return;
4337885954aSLewanczyk, Dawid                             }
43408777fb0SLewanczyk, Dawid                             // Go through all objects and update response with
43508777fb0SLewanczyk, Dawid                             // sensor data
436*1abe55efSEd Tanous                             for (const auto& objDictEntry : resp)
437*1abe55efSEd Tanous                             {
438aa2e59c1SEd Tanous                                 const std::string& objPath =
439*1abe55efSEd Tanous                                     static_cast<const std::string&>(
440*1abe55efSEd Tanous                                         objDictEntry.first);
441*1abe55efSEd Tanous                                 BMCWEB_LOG_DEBUG
442*1abe55efSEd Tanous                                     << "getManagedObjectsCb parsing object "
443588c3f0dSKowalski, Kamil                                     << objPath;
444e0d918bcSEd Tanous 
44508777fb0SLewanczyk, Dawid                                 std::vector<std::string> split;
44608777fb0SLewanczyk, Dawid                                 // Reserve space for
44703b5bae3SJames Feist                                 // /xyz/openbmc_project/sensors/<name>/<subname>
44808777fb0SLewanczyk, Dawid                                 split.reserve(6);
449*1abe55efSEd Tanous                                 boost::algorithm::split(split, objPath,
450*1abe55efSEd Tanous                                                         boost::is_any_of("/"));
451*1abe55efSEd Tanous                                 if (split.size() < 6)
452*1abe55efSEd Tanous                                 {
453*1abe55efSEd Tanous                                     BMCWEB_LOG_ERROR
454*1abe55efSEd Tanous                                         << "Got path that isn't long enough "
455588c3f0dSKowalski, Kamil                                         << objPath;
45608777fb0SLewanczyk, Dawid                                     continue;
45708777fb0SLewanczyk, Dawid                                 }
458*1abe55efSEd Tanous                                 // These indexes aren't intuitive, as
459*1abe55efSEd Tanous                                 // boost::split puts an empty string at the
460*1abe55efSEd Tanous                                 // beggining
46108777fb0SLewanczyk, Dawid                                 const std::string& sensorType = split[4];
46208777fb0SLewanczyk, Dawid                                 const std::string& sensorName = split[5];
46355c7b7a2SEd Tanous                                 BMCWEB_LOG_DEBUG << "sensorName " << sensorName
464*1abe55efSEd Tanous                                                  << " sensorType "
465*1abe55efSEd Tanous                                                  << sensorType;
466*1abe55efSEd Tanous                                 if (sensorNames.find(sensorName) ==
467*1abe55efSEd Tanous                                     sensorNames.end())
468*1abe55efSEd Tanous                                 {
469*1abe55efSEd Tanous                                     BMCWEB_LOG_ERROR << sensorName
470*1abe55efSEd Tanous                                                      << " not in sensor list ";
47108777fb0SLewanczyk, Dawid                                     continue;
47208777fb0SLewanczyk, Dawid                                 }
47308777fb0SLewanczyk, Dawid 
47408777fb0SLewanczyk, Dawid                                 const char* fieldName = nullptr;
475*1abe55efSEd Tanous                                 if (sensorType == "temperature")
476*1abe55efSEd Tanous                                 {
47708777fb0SLewanczyk, Dawid                                     fieldName = "Temperatures";
478*1abe55efSEd Tanous                                 }
479*1abe55efSEd Tanous                                 else if (sensorType == "fan" ||
480*1abe55efSEd Tanous                                          sensorType == "fan_tach")
481*1abe55efSEd Tanous                                 {
48208777fb0SLewanczyk, Dawid                                     fieldName = "Fans";
483*1abe55efSEd Tanous                                 }
484*1abe55efSEd Tanous                                 else if (sensorType == "voltage")
485*1abe55efSEd Tanous                                 {
48608777fb0SLewanczyk, Dawid                                     fieldName = "Voltages";
487*1abe55efSEd Tanous                                 }
488*1abe55efSEd Tanous                                 else if (sensorType == "current")
489*1abe55efSEd Tanous                                 {
49008777fb0SLewanczyk, Dawid                                     fieldName = "PowerSupply";
491*1abe55efSEd Tanous                                 }
492*1abe55efSEd Tanous                                 else if (sensorType == "power")
493*1abe55efSEd Tanous                                 {
49408777fb0SLewanczyk, Dawid                                     fieldName = "PowerSupply";
495*1abe55efSEd Tanous                                 }
496*1abe55efSEd Tanous                                 else
497*1abe55efSEd Tanous                                 {
498*1abe55efSEd Tanous                                     BMCWEB_LOG_ERROR
499*1abe55efSEd Tanous                                         << "Unsure how to handle sensorType "
50008777fb0SLewanczyk, Dawid                                         << sensorType;
50108777fb0SLewanczyk, Dawid                                     continue;
50208777fb0SLewanczyk, Dawid                                 }
50308777fb0SLewanczyk, Dawid 
50455c7b7a2SEd Tanous                                 nlohmann::json& tempArray =
50555c7b7a2SEd Tanous                                     SensorsAsyncResp->res.jsonValue[fieldName];
50608777fb0SLewanczyk, Dawid 
50708777fb0SLewanczyk, Dawid                                 // Create the array if it doesn't yet exist
508*1abe55efSEd Tanous                                 if (tempArray.is_array() == false)
509*1abe55efSEd Tanous                                 {
51055c7b7a2SEd Tanous                                     tempArray = nlohmann::json::array();
51108777fb0SLewanczyk, Dawid                                 }
51208777fb0SLewanczyk, Dawid 
51355c7b7a2SEd Tanous                                 tempArray.push_back(
514*1abe55efSEd Tanous                                     {{"@odata.id",
515*1abe55efSEd Tanous                                       "/redfish/v1/Chassis/" +
516588c3f0dSKowalski, Kamil                                           SensorsAsyncResp->chassisId +
517e0d918bcSEd Tanous                                           "/Thermal#/" + sensorName}});
51855c7b7a2SEd Tanous                                 nlohmann::json& sensorJson = tempArray.back();
519588c3f0dSKowalski, Kamil                                 objectInterfacesToJson(sensorName, sensorType,
520*1abe55efSEd Tanous                                                        objDictEntry.second,
521*1abe55efSEd Tanous                                                        sensorJson);
52208777fb0SLewanczyk, Dawid                             }
52355c7b7a2SEd Tanous                             BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
52408777fb0SLewanczyk, Dawid                         };
52555c7b7a2SEd Tanous                     crow::connections::systemBus->async_method_call(
5267885954aSLewanczyk, Dawid                         getManagedObjectsCb, connection, "/",
527*1abe55efSEd Tanous                         "org.freedesktop.DBus.ObjectManager",
528*1abe55efSEd Tanous                         "GetManagedObjects");
52908777fb0SLewanczyk, Dawid                 };
53055c7b7a2SEd Tanous                 BMCWEB_LOG_DEBUG << "getConnectionCb exit";
53108777fb0SLewanczyk, Dawid             };
53255c7b7a2SEd Tanous         // get connections and then pass it to get sensors
533*1abe55efSEd Tanous         getConnections(SensorsAsyncResp, sensorNames,
534*1abe55efSEd Tanous                        std::move(getConnectionCb));
53555c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassisCb exit";
53608777fb0SLewanczyk, Dawid     };
53708777fb0SLewanczyk, Dawid 
53855c7b7a2SEd Tanous     // get chassis information related to sensors
539588c3f0dSKowalski, Kamil     getChassis(SensorsAsyncResp, std::move(getChassisCb));
54055c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisData exit";
54108777fb0SLewanczyk, Dawid };
54208777fb0SLewanczyk, Dawid 
54308777fb0SLewanczyk, Dawid } // namespace redfish
544