xref: /openbmc/bmcweb/features/redfish/lib/sensors.hpp (revision 5f7d88c43ca389d0f053e0ce1aa3f3fc70f5f712)
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>
2508777fb0SLewanczyk, Dawid 
261abe55efSEd Tanous namespace redfish
271abe55efSEd 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  */
461abe55efSEd Tanous class SensorsAsyncResp
471abe55efSEd Tanous {
4808777fb0SLewanczyk, Dawid   public:
4955c7b7a2SEd Tanous     SensorsAsyncResp(crow::Response& response, const std::string& chassisId,
502474adfaSEd Tanous                      const std::initializer_list<const char*> types,
512474adfaSEd Tanous                      const std::string& subNode) :
522474adfaSEd Tanous         chassisId(chassisId),
532474adfaSEd Tanous         res(response), types(types), chassisSubNode(subNode)
541abe55efSEd Tanous     {
5555c7b7a2SEd Tanous         res.jsonValue["@odata.id"] =
5608777fb0SLewanczyk, Dawid             "/redfish/v1/Chassis/" + chassisId + "/Thermal";
5708777fb0SLewanczyk, Dawid     }
5808777fb0SLewanczyk, Dawid 
591abe55efSEd Tanous     ~SensorsAsyncResp()
601abe55efSEd Tanous     {
611abe55efSEd Tanous         if (res.result() == boost::beast::http::status::internal_server_error)
621abe55efSEd Tanous         {
631abe55efSEd Tanous             // Reset the json object to clear out any data that made it in
641abe55efSEd Tanous             // before the error happened todo(ed) handle error condition with
651abe55efSEd Tanous             // proper code
6655c7b7a2SEd Tanous             res.jsonValue = nlohmann::json::object();
6708777fb0SLewanczyk, Dawid         }
6808777fb0SLewanczyk, Dawid         res.end();
6908777fb0SLewanczyk, Dawid     }
70588c3f0dSKowalski, Kamil 
7155c7b7a2SEd Tanous     crow::Response& res;
72588c3f0dSKowalski, Kamil     std::string chassisId{};
7308777fb0SLewanczyk, Dawid     const std::vector<const char*> types;
742474adfaSEd Tanous     std::string chassisSubNode{};
7508777fb0SLewanczyk, Dawid };
7608777fb0SLewanczyk, Dawid 
7708777fb0SLewanczyk, Dawid /**
7808777fb0SLewanczyk, Dawid  * @brief Creates connections necessary for chassis sensors
79588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp Pointer to object holding response data
8008777fb0SLewanczyk, Dawid  * @param sensorNames Sensors retrieved from chassis
8108777fb0SLewanczyk, Dawid  * @param callback Callback for processing gathered connections
8208777fb0SLewanczyk, Dawid  */
8308777fb0SLewanczyk, Dawid template <typename Callback>
84588c3f0dSKowalski, Kamil void getConnections(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
8508777fb0SLewanczyk, Dawid                     const boost::container::flat_set<std::string>& sensorNames,
861abe55efSEd Tanous                     Callback&& callback)
871abe55efSEd Tanous {
8855c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getConnections enter";
8903b5bae3SJames Feist     const std::string path = "/xyz/openbmc_project/sensors";
9008777fb0SLewanczyk, Dawid     const std::array<std::string, 1> interfaces = {
9108777fb0SLewanczyk, Dawid         "xyz.openbmc_project.Sensor.Value"};
9208777fb0SLewanczyk, Dawid 
9308777fb0SLewanczyk, Dawid     // Response handler for parsing objects subtree
941abe55efSEd Tanous     auto respHandler = [callback{std::move(callback)}, SensorsAsyncResp,
951abe55efSEd Tanous                         sensorNames](const boost::system::error_code ec,
961abe55efSEd Tanous                                      const GetSubTreeType& subtree) {
9755c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getConnections resp_handler enter";
981abe55efSEd Tanous         if (ec)
991abe55efSEd Tanous         {
100*5f7d88c4SEd Tanous             messages::internalError(SensorsAsyncResp->res);
1011abe55efSEd Tanous             BMCWEB_LOG_ERROR << "getConnections resp_handler: Dbus error "
1021abe55efSEd Tanous                              << ec;
10308777fb0SLewanczyk, Dawid             return;
10408777fb0SLewanczyk, Dawid         }
10508777fb0SLewanczyk, Dawid 
10655c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
10708777fb0SLewanczyk, Dawid 
10808777fb0SLewanczyk, Dawid         // Make unique list of connections only for requested sensor types and
10908777fb0SLewanczyk, Dawid         // found in the chassis
11008777fb0SLewanczyk, Dawid         boost::container::flat_set<std::string> connections;
1111abe55efSEd Tanous         // Intrinsic to avoid malloc.  Most systems will have < 8 sensor
1121abe55efSEd Tanous         // producers
11308777fb0SLewanczyk, Dawid         connections.reserve(8);
11408777fb0SLewanczyk, Dawid 
11555c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames.size();
1161abe55efSEd Tanous         for (const std::string& tsensor : sensorNames)
1171abe55efSEd Tanous         {
11855c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor;
11908777fb0SLewanczyk, Dawid         }
12008777fb0SLewanczyk, Dawid 
12108777fb0SLewanczyk, Dawid         for (const std::pair<
12208777fb0SLewanczyk, Dawid                  std::string,
12308777fb0SLewanczyk, Dawid                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
1241abe55efSEd Tanous                  object : subtree)
1251abe55efSEd Tanous         {
1261abe55efSEd Tanous             for (const char* type : SensorsAsyncResp->types)
1271abe55efSEd Tanous             {
1281abe55efSEd Tanous                 if (boost::starts_with(object.first, type))
1291abe55efSEd Tanous                 {
13008777fb0SLewanczyk, Dawid                     auto lastPos = object.first.rfind('/');
1311abe55efSEd Tanous                     if (lastPos != std::string::npos)
1321abe55efSEd Tanous                     {
1331abe55efSEd Tanous                         std::string sensorName =
1341abe55efSEd Tanous                             object.first.substr(lastPos + 1);
13508777fb0SLewanczyk, Dawid 
1361abe55efSEd Tanous                         if (sensorNames.find(sensorName) != sensorNames.end())
1371abe55efSEd Tanous                         {
13855c7b7a2SEd Tanous                             // For each Connection name
1391abe55efSEd Tanous                             for (const std::pair<std::string,
1401abe55efSEd Tanous                                                  std::vector<std::string>>&
1411abe55efSEd Tanous                                      objData : object.second)
1421abe55efSEd Tanous                             {
1431abe55efSEd Tanous                                 BMCWEB_LOG_DEBUG << "Adding connection: "
1441abe55efSEd Tanous                                                  << objData.first;
14508777fb0SLewanczyk, Dawid                                 connections.insert(objData.first);
14608777fb0SLewanczyk, Dawid                             }
14708777fb0SLewanczyk, Dawid                         }
14808777fb0SLewanczyk, Dawid                     }
14908777fb0SLewanczyk, Dawid                     break;
15008777fb0SLewanczyk, Dawid                 }
15108777fb0SLewanczyk, Dawid             }
15208777fb0SLewanczyk, Dawid         }
15355c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections";
15408777fb0SLewanczyk, Dawid         callback(std::move(connections));
15555c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getConnections resp_handler exit";
15608777fb0SLewanczyk, Dawid     };
15708777fb0SLewanczyk, Dawid 
15808777fb0SLewanczyk, Dawid     // Make call to ObjectMapper to find all sensors objects
15955c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
16055c7b7a2SEd Tanous         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
1611abe55efSEd Tanous         "/xyz/openbmc_project/object_mapper",
1621abe55efSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 2, interfaces);
16355c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getConnections exit";
16408777fb0SLewanczyk, Dawid }
16508777fb0SLewanczyk, Dawid 
16608777fb0SLewanczyk, Dawid /**
16708777fb0SLewanczyk, Dawid  * @brief Retrieves requested chassis sensors and redundancy data from DBus .
168588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
16908777fb0SLewanczyk, Dawid  * @param callback  Callback for next step in gathered sensor processing
17008777fb0SLewanczyk, Dawid  */
17108777fb0SLewanczyk, Dawid template <typename Callback>
172588c3f0dSKowalski, Kamil void getChassis(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
1731abe55efSEd Tanous                 Callback&& callback)
1741abe55efSEd Tanous {
17555c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis enter";
17608777fb0SLewanczyk, Dawid     // Process response from EntityManager and extract chassis data
1771abe55efSEd Tanous     auto respHandler = [callback{std::move(callback)},
1781abe55efSEd Tanous                         SensorsAsyncResp](const boost::system::error_code ec,
1791abe55efSEd Tanous                                           ManagedObjectsVectorType& resp) {
18055c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassis respHandler enter";
1811abe55efSEd Tanous         if (ec)
1821abe55efSEd Tanous         {
18355c7b7a2SEd Tanous             BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec;
184*5f7d88c4SEd Tanous             messages::internalError(SensorsAsyncResp->res);
18508777fb0SLewanczyk, Dawid             return;
18608777fb0SLewanczyk, Dawid         }
18708777fb0SLewanczyk, Dawid         boost::container::flat_set<std::string> sensorNames;
18808777fb0SLewanczyk, Dawid 
189588c3f0dSKowalski, Kamil         //   SensorsAsyncResp->chassisId
190daf36e2eSEd Tanous         bool foundChassis = false;
191daf36e2eSEd Tanous         std::vector<std::string> split;
192daf36e2eSEd Tanous         // Reserve space for
193daf36e2eSEd Tanous         // /xyz/openbmc_project/inventory/<name>/<subname> + 3 subnames
194daf36e2eSEd Tanous         split.reserve(8);
195daf36e2eSEd Tanous 
1961abe55efSEd Tanous         for (const auto& objDictEntry : resp)
1971abe55efSEd Tanous         {
198daf36e2eSEd Tanous             const std::string& objectPath =
199daf36e2eSEd Tanous                 static_cast<const std::string&>(objDictEntry.first);
200daf36e2eSEd Tanous             boost::algorithm::split(split, objectPath, boost::is_any_of("/"));
2011abe55efSEd Tanous             if (split.size() < 2)
2021abe55efSEd Tanous             {
2031abe55efSEd Tanous                 BMCWEB_LOG_ERROR << "Got path that isn't long enough "
2041abe55efSEd Tanous                                  << objectPath;
205daf36e2eSEd Tanous                 split.clear();
206daf36e2eSEd Tanous                 continue;
207daf36e2eSEd Tanous             }
208daf36e2eSEd Tanous             const std::string& sensorName = split.end()[-1];
209daf36e2eSEd Tanous             const std::string& chassisName = split.end()[-2];
210daf36e2eSEd Tanous 
2111abe55efSEd Tanous             if (chassisName != SensorsAsyncResp->chassisId)
2121abe55efSEd Tanous             {
213daf36e2eSEd Tanous                 split.clear();
214daf36e2eSEd Tanous                 continue;
215daf36e2eSEd Tanous             }
21655c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "New sensor: " << sensorName;
217daf36e2eSEd Tanous             foundChassis = true;
21808777fb0SLewanczyk, Dawid             sensorNames.emplace(sensorName);
219daf36e2eSEd Tanous             split.clear();
22008777fb0SLewanczyk, Dawid         };
22155c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << sensorNames.size() << " Sensor names";
22208777fb0SLewanczyk, Dawid 
2231abe55efSEd Tanous         if (!foundChassis)
2241abe55efSEd Tanous         {
22555c7b7a2SEd Tanous             BMCWEB_LOG_INFO << "Unable to find chassis named "
226588c3f0dSKowalski, Kamil                             << SensorsAsyncResp->chassisId;
227f12894f8SJason M. Bills             messages::resourceNotFound(SensorsAsyncResp->res, "Chassis",
228f12894f8SJason M. Bills                                        SensorsAsyncResp->chassisId);
2291abe55efSEd Tanous         }
2301abe55efSEd Tanous         else
2311abe55efSEd Tanous         {
23208777fb0SLewanczyk, Dawid             callback(sensorNames);
23308777fb0SLewanczyk, Dawid         }
23455c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassis respHandler exit";
23508777fb0SLewanczyk, Dawid     };
23608777fb0SLewanczyk, Dawid 
23708777fb0SLewanczyk, Dawid     // Make call to EntityManager to find all chassis objects
23855c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
23955c7b7a2SEd Tanous         respHandler, "xyz.openbmc_project.EntityManager", "/",
2407885954aSLewanczyk, Dawid         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
24155c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis exit";
24208777fb0SLewanczyk, Dawid }
24308777fb0SLewanczyk, Dawid 
24408777fb0SLewanczyk, Dawid /**
24508777fb0SLewanczyk, Dawid  * @brief Builds a json sensor representation of a sensor.
24608777fb0SLewanczyk, Dawid  * @param sensorName  The name of the sensor to be built
247274fad5aSGunnar Mills  * @param sensorType  The type (temperature, fan_tach, etc) of the sensor to
24808777fb0SLewanczyk, Dawid  * build
24908777fb0SLewanczyk, Dawid  * @param interfacesDict  A dictionary of the interfaces and properties of said
25008777fb0SLewanczyk, Dawid  * interfaces to be built from
25108777fb0SLewanczyk, Dawid  * @param sensor_json  The json object to fill
25208777fb0SLewanczyk, Dawid  */
25308777fb0SLewanczyk, Dawid void objectInterfacesToJson(
25408777fb0SLewanczyk, Dawid     const std::string& sensorName, const std::string& sensorType,
25508777fb0SLewanczyk, Dawid     const boost::container::flat_map<
256aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>&
25708777fb0SLewanczyk, Dawid         interfacesDict,
2581abe55efSEd Tanous     nlohmann::json& sensor_json)
2591abe55efSEd Tanous {
26008777fb0SLewanczyk, Dawid     // We need a value interface before we can do anything with it
26155c7b7a2SEd Tanous     auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
2621abe55efSEd Tanous     if (valueIt == interfacesDict.end())
2631abe55efSEd Tanous     {
26455c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface";
26508777fb0SLewanczyk, Dawid         return;
26608777fb0SLewanczyk, Dawid     }
26708777fb0SLewanczyk, Dawid 
26808777fb0SLewanczyk, Dawid     // Assume values exist as is (10^0 == 1) if no scale exists
26908777fb0SLewanczyk, Dawid     int64_t scaleMultiplier = 0;
27008777fb0SLewanczyk, Dawid 
27155c7b7a2SEd Tanous     auto scaleIt = valueIt->second.find("Scale");
27208777fb0SLewanczyk, Dawid     // If a scale exists, pull value as int64, and use the scaling.
2731abe55efSEd Tanous     if (scaleIt != valueIt->second.end())
2741abe55efSEd Tanous     {
2751abe55efSEd Tanous         const int64_t* int64Value =
2761abe55efSEd Tanous             mapbox::getPtr<const int64_t>(scaleIt->second);
2771abe55efSEd Tanous         if (int64Value != nullptr)
2781abe55efSEd Tanous         {
27908777fb0SLewanczyk, Dawid             scaleMultiplier = *int64Value;
28008777fb0SLewanczyk, Dawid         }
28108777fb0SLewanczyk, Dawid     }
28208777fb0SLewanczyk, Dawid 
28308777fb0SLewanczyk, Dawid     sensor_json["MemberId"] = sensorName;
28408777fb0SLewanczyk, Dawid     sensor_json["Name"] = sensorName;
28508777fb0SLewanczyk, Dawid     sensor_json["Status"]["State"] = "Enabled";
28608777fb0SLewanczyk, Dawid     sensor_json["Status"]["Health"] = "OK";
28708777fb0SLewanczyk, Dawid 
28808777fb0SLewanczyk, Dawid     // Parameter to set to override the type we get from dbus, and force it to
28908777fb0SLewanczyk, Dawid     // int, regardless of what is available.  This is used for schemas like fan,
29008777fb0SLewanczyk, Dawid     // that require integers, not floats.
29108777fb0SLewanczyk, Dawid     bool forceToInt = false;
29208777fb0SLewanczyk, Dawid 
29308777fb0SLewanczyk, Dawid     const char* unit = "Reading";
2941abe55efSEd Tanous     if (sensorType == "temperature")
2951abe55efSEd Tanous     {
29608777fb0SLewanczyk, Dawid         unit = "ReadingCelsius";
2977885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature";
29808777fb0SLewanczyk, Dawid         // TODO(ed) Documentation says that path should be type fan_tach,
29908777fb0SLewanczyk, Dawid         // implementation seems to implement fan
3001abe55efSEd Tanous     }
3011abe55efSEd Tanous     else if (sensorType == "fan" || sensorType == "fan_tach")
3021abe55efSEd Tanous     {
30308777fb0SLewanczyk, Dawid         unit = "Reading";
30408777fb0SLewanczyk, Dawid         sensor_json["ReadingUnits"] = "RPM";
3057885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
30608777fb0SLewanczyk, Dawid         forceToInt = true;
3071abe55efSEd Tanous     }
3086f6d0d32SEd Tanous     else if (sensorType == "fan_pwm")
3096f6d0d32SEd Tanous     {
3106f6d0d32SEd Tanous         unit = "Reading";
3116f6d0d32SEd Tanous         sensor_json["ReadingUnits"] = "Percent";
3126f6d0d32SEd Tanous         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
3136f6d0d32SEd Tanous         forceToInt = true;
3146f6d0d32SEd Tanous     }
3151abe55efSEd Tanous     else if (sensorType == "voltage")
3161abe55efSEd Tanous     {
31708777fb0SLewanczyk, Dawid         unit = "ReadingVolts";
3187885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage";
3191abe55efSEd Tanous     }
3202474adfaSEd Tanous     else if (sensorType == "power")
3212474adfaSEd Tanous     {
3222474adfaSEd Tanous         unit = "LastPowerOutputWatts";
3232474adfaSEd Tanous     }
3241abe55efSEd Tanous     else
3251abe55efSEd Tanous     {
32655c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
32708777fb0SLewanczyk, Dawid         return;
32808777fb0SLewanczyk, Dawid     }
32908777fb0SLewanczyk, Dawid     // Map of dbus interface name, dbus property name and redfish property_name
33008777fb0SLewanczyk, Dawid     std::vector<std::tuple<const char*, const char*, const char*>> properties;
33108777fb0SLewanczyk, Dawid     properties.reserve(7);
33208777fb0SLewanczyk, Dawid 
33308777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
33408777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
33508777fb0SLewanczyk, Dawid                             "WarningHigh", "UpperThresholdNonCritical");
33608777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
33708777fb0SLewanczyk, Dawid                             "WarningLow", "LowerThresholdNonCritical");
33808777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
33908777fb0SLewanczyk, Dawid                             "CriticalHigh", "UpperThresholdCritical");
34008777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
34108777fb0SLewanczyk, Dawid                             "CriticalLow", "LowerThresholdCritical");
34208777fb0SLewanczyk, Dawid 
3432474adfaSEd Tanous     // TODO Need to get UpperThresholdFatal and LowerThresholdFatal
3442474adfaSEd Tanous 
3451abe55efSEd Tanous     if (sensorType == "temperature")
3461abe55efSEd Tanous     {
34708777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
34808777fb0SLewanczyk, Dawid                                 "MinReadingRangeTemp");
34908777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
35008777fb0SLewanczyk, Dawid                                 "MaxReadingRangeTemp");
3511abe55efSEd Tanous     }
3521abe55efSEd Tanous     else
3531abe55efSEd Tanous     {
35408777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
35508777fb0SLewanczyk, Dawid                                 "MinReadingRange");
35608777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
35708777fb0SLewanczyk, Dawid                                 "MaxReadingRange");
35808777fb0SLewanczyk, Dawid     }
35908777fb0SLewanczyk, Dawid 
36008777fb0SLewanczyk, Dawid     for (const std::tuple<const char*, const char*, const char*>& p :
3611abe55efSEd Tanous          properties)
3621abe55efSEd Tanous     {
36308777fb0SLewanczyk, Dawid         auto interfaceProperties = interfacesDict.find(std::get<0>(p));
3641abe55efSEd Tanous         if (interfaceProperties != interfacesDict.end())
3651abe55efSEd Tanous         {
36655c7b7a2SEd Tanous             auto valueIt = interfaceProperties->second.find(std::get<1>(p));
3671abe55efSEd Tanous             if (valueIt != interfaceProperties->second.end())
3681abe55efSEd Tanous             {
36955c7b7a2SEd Tanous                 const SensorVariant& valueVariant = valueIt->second;
37055c7b7a2SEd Tanous                 nlohmann::json& valueIt = sensor_json[std::get<2>(p)];
37108777fb0SLewanczyk, Dawid                 // Attempt to pull the int64 directly
3721abe55efSEd Tanous                 const int64_t* int64Value =
3731abe55efSEd Tanous                     mapbox::getPtr<const int64_t>(valueVariant);
37408777fb0SLewanczyk, Dawid 
3751abe55efSEd Tanous                 const double* doubleValue =
3761abe55efSEd Tanous                     mapbox::getPtr<const double>(valueVariant);
3776f6d0d32SEd Tanous                 double temp = 0.0;
3786f6d0d32SEd Tanous                 if (int64Value != nullptr)
3791abe55efSEd Tanous                 {
3806f6d0d32SEd Tanous                     temp = *int64Value;
3816f6d0d32SEd Tanous                 }
3826f6d0d32SEd Tanous                 else if (doubleValue != nullptr)
3831abe55efSEd Tanous                 {
3846f6d0d32SEd Tanous                     temp = *doubleValue;
3851abe55efSEd Tanous                 }
3861abe55efSEd Tanous                 else
3871abe55efSEd Tanous                 {
3886f6d0d32SEd Tanous                     BMCWEB_LOG_ERROR
3896f6d0d32SEd Tanous                         << "Got value interface that wasn't int or double";
3906f6d0d32SEd Tanous                     continue;
39108777fb0SLewanczyk, Dawid                 }
3926f6d0d32SEd Tanous                 temp = temp * std::pow(10, scaleMultiplier);
3936f6d0d32SEd Tanous                 if (forceToInt)
3946f6d0d32SEd Tanous                 {
3956f6d0d32SEd Tanous                     valueIt = static_cast<int64_t>(temp);
3966f6d0d32SEd Tanous                 }
3976f6d0d32SEd Tanous                 else
3986f6d0d32SEd Tanous                 {
3996f6d0d32SEd Tanous                     valueIt = temp;
40008777fb0SLewanczyk, Dawid                 }
40108777fb0SLewanczyk, Dawid             }
40208777fb0SLewanczyk, Dawid         }
40308777fb0SLewanczyk, Dawid     }
40455c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
40508777fb0SLewanczyk, Dawid }
40608777fb0SLewanczyk, Dawid 
40708777fb0SLewanczyk, Dawid /**
40808777fb0SLewanczyk, Dawid  * @brief Entry point for retrieving sensors data related to requested
40908777fb0SLewanczyk, Dawid  *        chassis.
410588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
41108777fb0SLewanczyk, Dawid  */
4121abe55efSEd Tanous void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
4131abe55efSEd Tanous {
41455c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisData enter";
415588c3f0dSKowalski, Kamil     auto getChassisCb = [&, SensorsAsyncResp](
416588c3f0dSKowalski, Kamil                             boost::container::flat_set<std::string>&
41708777fb0SLewanczyk, Dawid                                 sensorNames) {
41855c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassisCb enter";
419588c3f0dSKowalski, Kamil         auto getConnectionCb =
420588c3f0dSKowalski, Kamil             [&, SensorsAsyncResp, sensorNames](
421588c3f0dSKowalski, Kamil                 const boost::container::flat_set<std::string>& connections) {
42255c7b7a2SEd Tanous                 BMCWEB_LOG_DEBUG << "getConnectionCb enter";
42308777fb0SLewanczyk, Dawid                 // Get managed objects from all services exposing sensors
4241abe55efSEd Tanous                 for (const std::string& connection : connections)
4251abe55efSEd Tanous                 {
42608777fb0SLewanczyk, Dawid                     // Response handler to process managed objects
4271abe55efSEd Tanous                     auto getManagedObjectsCb =
4281abe55efSEd Tanous                         [&, SensorsAsyncResp,
4291abe55efSEd Tanous                          sensorNames](const boost::system::error_code ec,
43008777fb0SLewanczyk, Dawid                                       ManagedObjectsVectorType& resp) {
43155c7b7a2SEd Tanous                             BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
4321abe55efSEd Tanous                             if (ec)
4331abe55efSEd Tanous                             {
4341abe55efSEd Tanous                                 BMCWEB_LOG_ERROR
4351abe55efSEd Tanous                                     << "getManagedObjectsCb DBUS error: " << ec;
436*5f7d88c4SEd Tanous                                 messages::internalError(SensorsAsyncResp->res);
4377885954aSLewanczyk, Dawid                                 return;
4387885954aSLewanczyk, Dawid                             }
43908777fb0SLewanczyk, Dawid                             // Go through all objects and update response with
44008777fb0SLewanczyk, Dawid                             // sensor data
4411abe55efSEd Tanous                             for (const auto& objDictEntry : resp)
4421abe55efSEd Tanous                             {
443aa2e59c1SEd Tanous                                 const std::string& objPath =
4441abe55efSEd Tanous                                     static_cast<const std::string&>(
4451abe55efSEd Tanous                                         objDictEntry.first);
4461abe55efSEd Tanous                                 BMCWEB_LOG_DEBUG
4471abe55efSEd Tanous                                     << "getManagedObjectsCb parsing object "
448588c3f0dSKowalski, Kamil                                     << objPath;
449e0d918bcSEd Tanous 
45008777fb0SLewanczyk, Dawid                                 std::vector<std::string> split;
45108777fb0SLewanczyk, Dawid                                 // Reserve space for
45203b5bae3SJames Feist                                 // /xyz/openbmc_project/sensors/<name>/<subname>
45308777fb0SLewanczyk, Dawid                                 split.reserve(6);
4541abe55efSEd Tanous                                 boost::algorithm::split(split, objPath,
4551abe55efSEd Tanous                                                         boost::is_any_of("/"));
4561abe55efSEd Tanous                                 if (split.size() < 6)
4571abe55efSEd Tanous                                 {
4581abe55efSEd Tanous                                     BMCWEB_LOG_ERROR
4591abe55efSEd Tanous                                         << "Got path that isn't long enough "
460588c3f0dSKowalski, Kamil                                         << objPath;
46108777fb0SLewanczyk, Dawid                                     continue;
46208777fb0SLewanczyk, Dawid                                 }
4631abe55efSEd Tanous                                 // These indexes aren't intuitive, as
4641abe55efSEd Tanous                                 // boost::split puts an empty string at the
4651abe55efSEd Tanous                                 // beggining
46608777fb0SLewanczyk, Dawid                                 const std::string& sensorType = split[4];
46708777fb0SLewanczyk, Dawid                                 const std::string& sensorName = split[5];
46855c7b7a2SEd Tanous                                 BMCWEB_LOG_DEBUG << "sensorName " << sensorName
4691abe55efSEd Tanous                                                  << " sensorType "
4701abe55efSEd Tanous                                                  << sensorType;
4711abe55efSEd Tanous                                 if (sensorNames.find(sensorName) ==
4721abe55efSEd Tanous                                     sensorNames.end())
4731abe55efSEd Tanous                                 {
4741abe55efSEd Tanous                                     BMCWEB_LOG_ERROR << sensorName
4751abe55efSEd Tanous                                                      << " not in sensor list ";
47608777fb0SLewanczyk, Dawid                                     continue;
47708777fb0SLewanczyk, Dawid                                 }
47808777fb0SLewanczyk, Dawid 
47908777fb0SLewanczyk, Dawid                                 const char* fieldName = nullptr;
4801abe55efSEd Tanous                                 if (sensorType == "temperature")
4811abe55efSEd Tanous                                 {
48208777fb0SLewanczyk, Dawid                                     fieldName = "Temperatures";
4831abe55efSEd Tanous                                 }
4841abe55efSEd Tanous                                 else if (sensorType == "fan" ||
4856f6d0d32SEd Tanous                                          sensorType == "fan_tach" ||
4866f6d0d32SEd Tanous                                          sensorType == "fan_pwm")
4871abe55efSEd Tanous                                 {
48808777fb0SLewanczyk, Dawid                                     fieldName = "Fans";
4891abe55efSEd Tanous                                 }
4901abe55efSEd Tanous                                 else if (sensorType == "voltage")
4911abe55efSEd Tanous                                 {
49208777fb0SLewanczyk, Dawid                                     fieldName = "Voltages";
4931abe55efSEd Tanous                                 }
4941abe55efSEd Tanous                                 else if (sensorType == "current")
4951abe55efSEd Tanous                                 {
49608777fb0SLewanczyk, Dawid                                     fieldName = "PowerSupply";
4971abe55efSEd Tanous                                 }
4981abe55efSEd Tanous                                 else if (sensorType == "power")
4991abe55efSEd Tanous                                 {
50008777fb0SLewanczyk, Dawid                                     fieldName = "PowerSupply";
5011abe55efSEd Tanous                                 }
5021abe55efSEd Tanous                                 else
5031abe55efSEd Tanous                                 {
5041abe55efSEd Tanous                                     BMCWEB_LOG_ERROR
5051abe55efSEd Tanous                                         << "Unsure how to handle sensorType "
50608777fb0SLewanczyk, Dawid                                         << sensorType;
50708777fb0SLewanczyk, Dawid                                     continue;
50808777fb0SLewanczyk, Dawid                                 }
50908777fb0SLewanczyk, Dawid 
51055c7b7a2SEd Tanous                                 nlohmann::json& tempArray =
51155c7b7a2SEd Tanous                                     SensorsAsyncResp->res.jsonValue[fieldName];
51208777fb0SLewanczyk, Dawid 
51355c7b7a2SEd Tanous                                 tempArray.push_back(
5141abe55efSEd Tanous                                     {{"@odata.id",
5151abe55efSEd Tanous                                       "/redfish/v1/Chassis/" +
5162474adfaSEd Tanous                                           SensorsAsyncResp->chassisId + "/" +
5172474adfaSEd Tanous                                           SensorsAsyncResp->chassisSubNode +
5182474adfaSEd Tanous                                           "#/" + fieldName + "/" +
5196f6d0d32SEd Tanous                                           std::to_string(tempArray.size())}});
52055c7b7a2SEd Tanous                                 nlohmann::json& sensorJson = tempArray.back();
5216f6d0d32SEd Tanous 
522588c3f0dSKowalski, Kamil                                 objectInterfacesToJson(sensorName, sensorType,
5231abe55efSEd Tanous                                                        objDictEntry.second,
5241abe55efSEd Tanous                                                        sensorJson);
52508777fb0SLewanczyk, Dawid                             }
52655c7b7a2SEd Tanous                             BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
52708777fb0SLewanczyk, Dawid                         };
52855c7b7a2SEd Tanous                     crow::connections::systemBus->async_method_call(
5297885954aSLewanczyk, Dawid                         getManagedObjectsCb, connection, "/",
5301abe55efSEd Tanous                         "org.freedesktop.DBus.ObjectManager",
5311abe55efSEd Tanous                         "GetManagedObjects");
53208777fb0SLewanczyk, Dawid                 };
53355c7b7a2SEd Tanous                 BMCWEB_LOG_DEBUG << "getConnectionCb exit";
53408777fb0SLewanczyk, Dawid             };
53555c7b7a2SEd Tanous         // get connections and then pass it to get sensors
5361abe55efSEd Tanous         getConnections(SensorsAsyncResp, sensorNames,
5371abe55efSEd Tanous                        std::move(getConnectionCb));
53855c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassisCb exit";
53908777fb0SLewanczyk, Dawid     };
54008777fb0SLewanczyk, Dawid 
54155c7b7a2SEd Tanous     // get chassis information related to sensors
542588c3f0dSKowalski, Kamil     getChassis(SensorsAsyncResp, std::move(getChassisCb));
54355c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisData exit";
54408777fb0SLewanczyk, Dawid };
54508777fb0SLewanczyk, Dawid 
54608777fb0SLewanczyk, Dawid } // namespace redfish
547