xref: /openbmc/bmcweb/features/redfish/lib/sensors.hpp (revision 274fad5ad0e7634d9ed3e174695136e674688e0c)
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>
1908777fb0SLewanczyk, Dawid #include <dbus_singleton.hpp>
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>
2408777fb0SLewanczyk, Dawid #include <boost/variant.hpp>
2508777fb0SLewanczyk, Dawid #include <boost/variant/get.hpp>
2608777fb0SLewanczyk, Dawid 
2708777fb0SLewanczyk, Dawid namespace redfish {
2808777fb0SLewanczyk, Dawid 
2908777fb0SLewanczyk, Dawid constexpr const char* DBUS_SENSOR_PREFIX = "/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 
3508777fb0SLewanczyk, Dawid using ManagedObjectsVectorType = std::vector<std::pair<
3608777fb0SLewanczyk, Dawid     dbus::object_path,
3708777fb0SLewanczyk, Dawid     boost::container::flat_map<
3808777fb0SLewanczyk, Dawid         std::string,
3908777fb0SLewanczyk, Dawid         boost::container::flat_map<dbus::string, dbus::dbus_variant>>>>;
4008777fb0SLewanczyk, Dawid 
4108777fb0SLewanczyk, Dawid /**
4208777fb0SLewanczyk, Dawid  * AsyncResp
4308777fb0SLewanczyk, Dawid  * Gathers data needed for response processing after async calls are done
4408777fb0SLewanczyk, Dawid  */
4508777fb0SLewanczyk, Dawid class AsyncResp {
4608777fb0SLewanczyk, Dawid  public:
4708777fb0SLewanczyk, Dawid   AsyncResp(crow::response& response, const std::string& chassisId,
4808777fb0SLewanczyk, Dawid             const std::initializer_list<const char*> types)
4908777fb0SLewanczyk, Dawid       : chassisId(chassisId), res(response), types(types) {
5008777fb0SLewanczyk, Dawid     res.json_value["@odata.id"] =
5108777fb0SLewanczyk, Dawid         "/redfish/v1/Chassis/" + chassisId + "/Thermal";
5208777fb0SLewanczyk, Dawid   }
5308777fb0SLewanczyk, Dawid 
5408777fb0SLewanczyk, Dawid   ~AsyncResp() {
5508777fb0SLewanczyk, Dawid     if (res.code != static_cast<int>(HttpRespCode::OK)) {
5608777fb0SLewanczyk, Dawid       // Reset the json object to clear out any data that made it in before the
5708777fb0SLewanczyk, Dawid       // error happened
5808777fb0SLewanczyk, Dawid       // todo(ed) handle error condition with proper code
5908777fb0SLewanczyk, Dawid       res.json_value = nlohmann::json::object();
6008777fb0SLewanczyk, Dawid     }
6108777fb0SLewanczyk, Dawid     res.end();
6208777fb0SLewanczyk, Dawid   }
6308777fb0SLewanczyk, Dawid   void setErrorStatus() {
6408777fb0SLewanczyk, Dawid     res.code = static_cast<int>(HttpRespCode::INTERNAL_ERROR);
6508777fb0SLewanczyk, Dawid   }
6608777fb0SLewanczyk, Dawid 
6708777fb0SLewanczyk, Dawid   std::string chassisId{};
6808777fb0SLewanczyk, Dawid   crow::response& res;
6908777fb0SLewanczyk, Dawid   const std::vector<const char*> types;
7008777fb0SLewanczyk, Dawid };
7108777fb0SLewanczyk, Dawid 
7208777fb0SLewanczyk, Dawid /**
7308777fb0SLewanczyk, Dawid  * @brief Creates connections necessary for chassis sensors
7408777fb0SLewanczyk, Dawid  * @param asyncResp Pointer to object holding response data
7508777fb0SLewanczyk, Dawid  * @param sensorNames Sensors retrieved from chassis
7608777fb0SLewanczyk, Dawid  * @param callback Callback for processing gathered connections
7708777fb0SLewanczyk, Dawid  */
7808777fb0SLewanczyk, Dawid template <typename Callback>
7908777fb0SLewanczyk, Dawid void getConnections(const std::shared_ptr<AsyncResp>& asyncResp,
8008777fb0SLewanczyk, Dawid                     const boost::container::flat_set<std::string>& sensorNames,
8108777fb0SLewanczyk, Dawid                     Callback&& callback) {
8208777fb0SLewanczyk, Dawid   CROW_LOG_DEBUG << "getConnections";
8308777fb0SLewanczyk, Dawid   const std::string path = "/xyz/openbmc_project/Sensors";
8408777fb0SLewanczyk, Dawid   const std::array<std::string, 1> interfaces = {
8508777fb0SLewanczyk, Dawid       "xyz.openbmc_project.Sensor.Value"};
8608777fb0SLewanczyk, Dawid   const dbus::endpoint object_mapper(
8708777fb0SLewanczyk, Dawid       "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper",
8808777fb0SLewanczyk, Dawid       "xyz.openbmc_project.ObjectMapper", "GetSubTree");
8908777fb0SLewanczyk, Dawid 
9008777fb0SLewanczyk, Dawid   // Response handler for parsing objects subtree
9108777fb0SLewanczyk, Dawid   auto resp_handler = [ callback{std::move(callback)}, asyncResp, sensorNames ](
9208777fb0SLewanczyk, Dawid       const boost::system::error_code ec, const GetSubTreeType& subtree) {
9308777fb0SLewanczyk, Dawid     if (ec != 0) {
9408777fb0SLewanczyk, Dawid       asyncResp->setErrorStatus();
9508777fb0SLewanczyk, Dawid       CROW_LOG_ERROR << "Dbus error " << ec;
9608777fb0SLewanczyk, Dawid       return;
9708777fb0SLewanczyk, Dawid     }
9808777fb0SLewanczyk, Dawid 
9908777fb0SLewanczyk, Dawid     CROW_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
10008777fb0SLewanczyk, Dawid 
10108777fb0SLewanczyk, Dawid     // Make unique list of connections only for requested sensor types and
10208777fb0SLewanczyk, Dawid     // found in the chassis
10308777fb0SLewanczyk, Dawid     boost::container::flat_set<std::string> connections;
10408777fb0SLewanczyk, Dawid     // Intrinsic to avoid malloc.  Most systems will have < 8 sensor producers
10508777fb0SLewanczyk, Dawid     connections.reserve(8);
10608777fb0SLewanczyk, Dawid 
10708777fb0SLewanczyk, Dawid     CROW_LOG_DEBUG << "sensorNames list cout: " << sensorNames.size();
10808777fb0SLewanczyk, Dawid     for (const std::string& tsensor : sensorNames) {
10908777fb0SLewanczyk, Dawid       CROW_LOG_DEBUG << "Sensor to find: " << tsensor;
11008777fb0SLewanczyk, Dawid     }
11108777fb0SLewanczyk, Dawid 
11208777fb0SLewanczyk, Dawid     for (const std::pair<
11308777fb0SLewanczyk, Dawid              std::string,
11408777fb0SLewanczyk, Dawid              std::vector<std::pair<std::string, std::vector<std::string>>>>&
11508777fb0SLewanczyk, Dawid              object : subtree) {
11608777fb0SLewanczyk, Dawid       for (const char* type : asyncResp->types) {
11708777fb0SLewanczyk, Dawid         if (boost::starts_with(object.first, type)) {
11808777fb0SLewanczyk, Dawid           auto lastPos = object.first.rfind('/');
11908777fb0SLewanczyk, Dawid           if (lastPos != std::string::npos) {
12008777fb0SLewanczyk, Dawid             std::string sensorName = object.first.substr(lastPos + 1);
12108777fb0SLewanczyk, Dawid 
12208777fb0SLewanczyk, Dawid             if (sensorNames.find(sensorName) != sensorNames.end()) {
12308777fb0SLewanczyk, Dawid               // For each connection name
12408777fb0SLewanczyk, Dawid               for (const std::pair<std::string, std::vector<std::string>>&
12508777fb0SLewanczyk, Dawid                        objData : object.second) {
12608777fb0SLewanczyk, Dawid                 connections.insert(objData.first);
12708777fb0SLewanczyk, Dawid               }
12808777fb0SLewanczyk, Dawid             }
12908777fb0SLewanczyk, Dawid           }
13008777fb0SLewanczyk, Dawid           break;
13108777fb0SLewanczyk, Dawid         }
13208777fb0SLewanczyk, Dawid       }
13308777fb0SLewanczyk, Dawid     }
13408777fb0SLewanczyk, Dawid     CROW_LOG_DEBUG << "Found " << connections.size() << " connections";
13508777fb0SLewanczyk, Dawid     callback(std::move(connections));
13608777fb0SLewanczyk, Dawid   };
13708777fb0SLewanczyk, Dawid 
13808777fb0SLewanczyk, Dawid   // Make call to ObjectMapper to find all sensors objects
13908777fb0SLewanczyk, Dawid   crow::connections::system_bus->async_method_call(resp_handler, object_mapper,
14008777fb0SLewanczyk, Dawid                                                    path, 2, interfaces);
14108777fb0SLewanczyk, Dawid }
14208777fb0SLewanczyk, Dawid 
14308777fb0SLewanczyk, Dawid /**
14408777fb0SLewanczyk, Dawid  * @brief Retrieves requested chassis sensors and redundancy data from DBus .
14508777fb0SLewanczyk, Dawid  * @param asyncResp   Pointer to object holding response data
14608777fb0SLewanczyk, Dawid  * @param callback  Callback for next step in gathered sensor processing
14708777fb0SLewanczyk, Dawid  */
14808777fb0SLewanczyk, Dawid template <typename Callback>
14908777fb0SLewanczyk, Dawid void getChassis(const std::shared_ptr<AsyncResp>& asyncResp,
15008777fb0SLewanczyk, Dawid                 Callback&& callback) {
15108777fb0SLewanczyk, Dawid   CROW_LOG_DEBUG << "getChassis Done";
15208777fb0SLewanczyk, Dawid   const dbus::endpoint entityManager = {
15308777fb0SLewanczyk, Dawid       "xyz.openbmc_project.EntityManager",
15408777fb0SLewanczyk, Dawid       "/xyz/openbmc_project/Inventory/Item/Chassis",
15508777fb0SLewanczyk, Dawid       "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"};
15608777fb0SLewanczyk, Dawid 
15708777fb0SLewanczyk, Dawid   // Process response from EntityManager and extract chassis data
15808777fb0SLewanczyk, Dawid   auto resp_handler = [ callback{std::move(callback)}, asyncResp ](
15908777fb0SLewanczyk, Dawid       const boost::system::error_code ec, ManagedObjectsVectorType& resp) {
16008777fb0SLewanczyk, Dawid     CROW_LOG_DEBUG << "getChassis resp_handler called back Done";
16108777fb0SLewanczyk, Dawid     if (ec) {
16208777fb0SLewanczyk, Dawid       CROW_LOG_ERROR << "getChassis resp_handler got error " << ec;
16308777fb0SLewanczyk, Dawid       asyncResp->setErrorStatus();
16408777fb0SLewanczyk, Dawid       return;
16508777fb0SLewanczyk, Dawid     }
16608777fb0SLewanczyk, Dawid     boost::container::flat_set<std::string> sensorNames;
16708777fb0SLewanczyk, Dawid     const std::string chassis_prefix =
16808777fb0SLewanczyk, Dawid         "/xyz/openbmc_project/Inventory/Item/Chassis/" + asyncResp->chassisId +
16908777fb0SLewanczyk, Dawid         '/';
17008777fb0SLewanczyk, Dawid     CROW_LOG_DEBUG << "Chassis Prefix " << chassis_prefix;
17108777fb0SLewanczyk, Dawid     bool foundChassis = false;
17208777fb0SLewanczyk, Dawid     for (const auto& objDictEntry : resp) {
17308777fb0SLewanczyk, Dawid       if (boost::starts_with(objDictEntry.first.value, chassis_prefix)) {
17408777fb0SLewanczyk, Dawid         foundChassis = true;
17508777fb0SLewanczyk, Dawid         const std::string sensorName =
17608777fb0SLewanczyk, Dawid             objDictEntry.first.value.substr(chassis_prefix.size());
17708777fb0SLewanczyk, Dawid         // Make sure this isn't a subobject (like a threshold)
17808777fb0SLewanczyk, Dawid         const std::size_t sensorPos = sensorName.find('/');
17908777fb0SLewanczyk, Dawid         if (sensorPos == std::string::npos) {
18008777fb0SLewanczyk, Dawid           CROW_LOG_DEBUG << "Adding sensor " << sensorName;
18108777fb0SLewanczyk, Dawid 
18208777fb0SLewanczyk, Dawid           sensorNames.emplace(sensorName);
18308777fb0SLewanczyk, Dawid         }
18408777fb0SLewanczyk, Dawid       }
18508777fb0SLewanczyk, Dawid     };
18608777fb0SLewanczyk, Dawid     CROW_LOG_DEBUG << "Found " << sensorNames.size() << " Sensor names";
18708777fb0SLewanczyk, Dawid 
18808777fb0SLewanczyk, Dawid     if (!foundChassis) {
18908777fb0SLewanczyk, Dawid       CROW_LOG_INFO << "Unable to find chassis named " << asyncResp->chassisId;
19008777fb0SLewanczyk, Dawid       asyncResp->res.code = static_cast<int>(HttpRespCode::NOT_FOUND);
19108777fb0SLewanczyk, Dawid     } else {
19208777fb0SLewanczyk, Dawid       callback(sensorNames);
19308777fb0SLewanczyk, Dawid     }
19408777fb0SLewanczyk, Dawid   };
19508777fb0SLewanczyk, Dawid 
19608777fb0SLewanczyk, Dawid   // Make call to EntityManager to find all chassis objects
19708777fb0SLewanczyk, Dawid   crow::connections::system_bus->async_method_call(resp_handler, entityManager);
19808777fb0SLewanczyk, Dawid }
19908777fb0SLewanczyk, Dawid 
20008777fb0SLewanczyk, Dawid /**
20108777fb0SLewanczyk, Dawid  * @brief Builds a json sensor representation of a sensor.
20208777fb0SLewanczyk, Dawid  * @param sensorName  The name of the sensor to be built
203*274fad5aSGunnar Mills  * @param sensorType  The type (temperature, fan_tach, etc) of the sensor to
20408777fb0SLewanczyk, Dawid  * build
20508777fb0SLewanczyk, Dawid  * @param interfacesDict  A dictionary of the interfaces and properties of said
20608777fb0SLewanczyk, Dawid  * interfaces to be built from
20708777fb0SLewanczyk, Dawid  * @param sensor_json  The json object to fill
20808777fb0SLewanczyk, Dawid  */
20908777fb0SLewanczyk, Dawid void objectInterfacesToJson(
21008777fb0SLewanczyk, Dawid     const std::string& sensorName, const std::string& sensorType,
21108777fb0SLewanczyk, Dawid     const boost::container::flat_map<
21208777fb0SLewanczyk, Dawid         std::string,
21308777fb0SLewanczyk, Dawid         boost::container::flat_map<dbus::string, dbus::dbus_variant>>&
21408777fb0SLewanczyk, Dawid         interfacesDict,
21508777fb0SLewanczyk, Dawid     nlohmann::json& sensor_json) {
21608777fb0SLewanczyk, Dawid   // We need a value interface before we can do anything with it
21708777fb0SLewanczyk, Dawid   auto value_it = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
21808777fb0SLewanczyk, Dawid   if (value_it == interfacesDict.end()) {
21908777fb0SLewanczyk, Dawid     CROW_LOG_ERROR << "Sensor doesn't have a value interface";
22008777fb0SLewanczyk, Dawid     return;
22108777fb0SLewanczyk, Dawid   }
22208777fb0SLewanczyk, Dawid 
22308777fb0SLewanczyk, Dawid   // Assume values exist as is (10^0 == 1) if no scale exists
22408777fb0SLewanczyk, Dawid   int64_t scaleMultiplier = 0;
22508777fb0SLewanczyk, Dawid 
22608777fb0SLewanczyk, Dawid   auto scale_it = value_it->second.find("Scale");
22708777fb0SLewanczyk, Dawid   // If a scale exists, pull value as int64, and use the scaling.
22808777fb0SLewanczyk, Dawid   if (scale_it != value_it->second.end()) {
22908777fb0SLewanczyk, Dawid     const int64_t* int64Value = boost::get<int64_t>(&scale_it->second);
23008777fb0SLewanczyk, Dawid     if (int64Value != nullptr) {
23108777fb0SLewanczyk, Dawid       scaleMultiplier = *int64Value;
23208777fb0SLewanczyk, Dawid     }
23308777fb0SLewanczyk, Dawid   }
23408777fb0SLewanczyk, Dawid 
23508777fb0SLewanczyk, Dawid   sensor_json["MemberId"] = sensorName;
23608777fb0SLewanczyk, Dawid   sensor_json["Name"] = sensorName;
23708777fb0SLewanczyk, Dawid   sensor_json["Status"]["State"] = "Enabled";
23808777fb0SLewanczyk, Dawid   sensor_json["Status"]["Health"] = "OK";
23908777fb0SLewanczyk, Dawid 
24008777fb0SLewanczyk, Dawid   // Parameter to set to override the type we get from dbus, and force it to
24108777fb0SLewanczyk, Dawid   // int, regardless of what is available.  This is used for schemas like fan,
24208777fb0SLewanczyk, Dawid   // that require integers, not floats.
24308777fb0SLewanczyk, Dawid   bool forceToInt = false;
24408777fb0SLewanczyk, Dawid 
24508777fb0SLewanczyk, Dawid   const char* unit = "Reading";
24608777fb0SLewanczyk, Dawid   if (sensorType == "temperature") {
24708777fb0SLewanczyk, Dawid     unit = "ReadingCelsius";
24808777fb0SLewanczyk, Dawid     // TODO(ed) Documentation says that path should be type fan_tach,
24908777fb0SLewanczyk, Dawid     // implementation seems to implement fan
25008777fb0SLewanczyk, Dawid   } else if (sensorType == "fan" || sensorType == "fan_tach") {
25108777fb0SLewanczyk, Dawid     unit = "Reading";
25208777fb0SLewanczyk, Dawid     sensor_json["ReadingUnits"] = "RPM";
25308777fb0SLewanczyk, Dawid     forceToInt = true;
25408777fb0SLewanczyk, Dawid   } else if (sensorType == "voltage") {
25508777fb0SLewanczyk, Dawid     unit = "ReadingVolts";
25608777fb0SLewanczyk, Dawid   } else {
25708777fb0SLewanczyk, Dawid     CROW_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
25808777fb0SLewanczyk, Dawid     return;
25908777fb0SLewanczyk, Dawid   }
26008777fb0SLewanczyk, Dawid   // Map of dbus interface name, dbus property name and redfish property_name
26108777fb0SLewanczyk, Dawid   std::vector<std::tuple<const char*, const char*, const char*>> properties;
26208777fb0SLewanczyk, Dawid   properties.reserve(7);
26308777fb0SLewanczyk, Dawid 
26408777fb0SLewanczyk, Dawid   properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
26508777fb0SLewanczyk, Dawid   properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
26608777fb0SLewanczyk, Dawid                           "WarningHigh", "UpperThresholdNonCritical");
26708777fb0SLewanczyk, Dawid   properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
26808777fb0SLewanczyk, Dawid                           "WarningLow", "LowerThresholdNonCritical");
26908777fb0SLewanczyk, Dawid   properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
27008777fb0SLewanczyk, Dawid                           "CriticalHigh", "UpperThresholdCritical");
27108777fb0SLewanczyk, Dawid   properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
27208777fb0SLewanczyk, Dawid                           "CriticalLow", "LowerThresholdCritical");
27308777fb0SLewanczyk, Dawid 
27408777fb0SLewanczyk, Dawid   if (sensorType == "temperature") {
27508777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
27608777fb0SLewanczyk, Dawid                             "MinReadingRangeTemp");
27708777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
27808777fb0SLewanczyk, Dawid                             "MaxReadingRangeTemp");
27908777fb0SLewanczyk, Dawid   } else {
28008777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
28108777fb0SLewanczyk, Dawid                             "MinReadingRange");
28208777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
28308777fb0SLewanczyk, Dawid                             "MaxReadingRange");
28408777fb0SLewanczyk, Dawid   }
28508777fb0SLewanczyk, Dawid 
28608777fb0SLewanczyk, Dawid   for (const std::tuple<const char*, const char*, const char*>& p :
28708777fb0SLewanczyk, Dawid        properties) {
28808777fb0SLewanczyk, Dawid     auto interfaceProperties = interfacesDict.find(std::get<0>(p));
28908777fb0SLewanczyk, Dawid     if (interfaceProperties != interfacesDict.end()) {
29008777fb0SLewanczyk, Dawid       auto value_it = interfaceProperties->second.find(std::get<1>(p));
29108777fb0SLewanczyk, Dawid       if (value_it != interfaceProperties->second.end()) {
29208777fb0SLewanczyk, Dawid         const dbus::dbus_variant& valueVariant = value_it->second;
29308777fb0SLewanczyk, Dawid         nlohmann::json& value_it = sensor_json[std::get<2>(p)];
29408777fb0SLewanczyk, Dawid         // Attempt to pull the int64 directly
29508777fb0SLewanczyk, Dawid         const int64_t* int64Value = boost::get<int64_t>(&valueVariant);
29608777fb0SLewanczyk, Dawid 
29708777fb0SLewanczyk, Dawid         if (int64Value != nullptr) {
29808777fb0SLewanczyk, Dawid           if (forceToInt || scaleMultiplier >= 0) {
29908777fb0SLewanczyk, Dawid             value_it = *int64Value * std::pow(10, scaleMultiplier);
30008777fb0SLewanczyk, Dawid           } else {
30108777fb0SLewanczyk, Dawid             value_it = *int64Value *
30208777fb0SLewanczyk, Dawid                        std::pow(10, static_cast<double>(scaleMultiplier));
30308777fb0SLewanczyk, Dawid           }
30408777fb0SLewanczyk, Dawid         }
30508777fb0SLewanczyk, Dawid         // Attempt to pull the float directly
30608777fb0SLewanczyk, Dawid         const double* doubleValue = boost::get<double>(&valueVariant);
30708777fb0SLewanczyk, Dawid 
30808777fb0SLewanczyk, Dawid         if (doubleValue != nullptr) {
30908777fb0SLewanczyk, Dawid           if (!forceToInt) {
31008777fb0SLewanczyk, Dawid             value_it = *doubleValue *
31108777fb0SLewanczyk, Dawid                        std::pow(10, static_cast<double>(scaleMultiplier));
31208777fb0SLewanczyk, Dawid           } else {
31308777fb0SLewanczyk, Dawid             value_it = static_cast<int64_t>(*doubleValue *
31408777fb0SLewanczyk, Dawid                                             std::pow(10, scaleMultiplier));
31508777fb0SLewanczyk, Dawid           }
31608777fb0SLewanczyk, Dawid         }
31708777fb0SLewanczyk, Dawid       }
31808777fb0SLewanczyk, Dawid     }
31908777fb0SLewanczyk, Dawid   }
32008777fb0SLewanczyk, Dawid }
32108777fb0SLewanczyk, Dawid 
32208777fb0SLewanczyk, Dawid /**
32308777fb0SLewanczyk, Dawid  * @brief Entry point for retrieving sensors data related to requested
32408777fb0SLewanczyk, Dawid  *        chassis.
32508777fb0SLewanczyk, Dawid  * @param asyncResp   Pointer to object holding response data
32608777fb0SLewanczyk, Dawid  */
32708777fb0SLewanczyk, Dawid void getChassisData(const std::shared_ptr<AsyncResp>& asyncResp) {
32808777fb0SLewanczyk, Dawid   CROW_LOG_DEBUG << "getChassisData";
32908777fb0SLewanczyk, Dawid   auto getChassisCb = [&, asyncResp](boost::container::flat_set<std::string>&
33008777fb0SLewanczyk, Dawid                                          sensorNames) {
33108777fb0SLewanczyk, Dawid     CROW_LOG_DEBUG << "getChassisCb Done";
33208777fb0SLewanczyk, Dawid     auto getConnectionCb =
33308777fb0SLewanczyk, Dawid         [&, asyncResp, sensorNames](
33408777fb0SLewanczyk, Dawid             const boost::container::flat_set<std::string>& connections) {
33508777fb0SLewanczyk, Dawid           CROW_LOG_DEBUG << "getConnectionCb Done";
33608777fb0SLewanczyk, Dawid           // Get managed objects from all services exposing sensors
33708777fb0SLewanczyk, Dawid           for (const std::string& connection : connections) {
33808777fb0SLewanczyk, Dawid             // Response handler to process managed objects
33908777fb0SLewanczyk, Dawid             auto getManagedObjectsCb = [&, asyncResp, sensorNames](
34008777fb0SLewanczyk, Dawid                                            const boost::system::error_code ec,
34108777fb0SLewanczyk, Dawid                                            ManagedObjectsVectorType& resp) {
34208777fb0SLewanczyk, Dawid               // Go through all objects and update response with
34308777fb0SLewanczyk, Dawid               // sensor data
34408777fb0SLewanczyk, Dawid               for (const auto& objDictEntry : resp) {
34508777fb0SLewanczyk, Dawid                 const std::string& objPath = objDictEntry.first.value;
34608777fb0SLewanczyk, Dawid                 CROW_LOG_DEBUG << "getManagedObjectsCb parsing object "
34708777fb0SLewanczyk, Dawid                                << objPath;
34808777fb0SLewanczyk, Dawid                 if (!boost::starts_with(objPath, DBUS_SENSOR_PREFIX)) {
34908777fb0SLewanczyk, Dawid                   CROW_LOG_ERROR << "Got path that isn't in sensor namespace: "
35008777fb0SLewanczyk, Dawid                                  << objPath;
35108777fb0SLewanczyk, Dawid                   continue;
35208777fb0SLewanczyk, Dawid                 }
35308777fb0SLewanczyk, Dawid                 std::vector<std::string> split;
35408777fb0SLewanczyk, Dawid                 // Reserve space for
35508777fb0SLewanczyk, Dawid                 // /xyz/openbmc_project/Sensors/<name>/<subname>
35608777fb0SLewanczyk, Dawid                 split.reserve(6);
35708777fb0SLewanczyk, Dawid                 boost::algorithm::split(split, objPath, boost::is_any_of("/"));
35808777fb0SLewanczyk, Dawid                 if (split.size() < 6) {
35908777fb0SLewanczyk, Dawid                   CROW_LOG_ERROR << "Got path that isn't long enough "
36008777fb0SLewanczyk, Dawid                                  << objPath;
36108777fb0SLewanczyk, Dawid                   continue;
36208777fb0SLewanczyk, Dawid                 }
36308777fb0SLewanczyk, Dawid                 // These indexes aren't intuitive, as boost::split puts an empty
364*274fad5aSGunnar Mills                 // string at the beginning
36508777fb0SLewanczyk, Dawid                 const std::string& sensorType = split[4];
36608777fb0SLewanczyk, Dawid                 const std::string& sensorName = split[5];
36708777fb0SLewanczyk, Dawid                 CROW_LOG_DEBUG << "sensorName " << sensorName << " sensorType "
36808777fb0SLewanczyk, Dawid                                << sensorType;
36908777fb0SLewanczyk, Dawid                 if (sensorNames.find(sensorName) == sensorNames.end()) {
37008777fb0SLewanczyk, Dawid                   CROW_LOG_ERROR << sensorName << " not in sensor list ";
37108777fb0SLewanczyk, Dawid                   continue;
37208777fb0SLewanczyk, Dawid                 }
37308777fb0SLewanczyk, Dawid 
37408777fb0SLewanczyk, Dawid                 const char* fieldName = nullptr;
37508777fb0SLewanczyk, Dawid                 if (sensorType == "temperature") {
37608777fb0SLewanczyk, Dawid                   fieldName = "Temperatures";
37708777fb0SLewanczyk, Dawid                 } else if (sensorType == "fan" || sensorType == "fan_tach") {
37808777fb0SLewanczyk, Dawid                   fieldName = "Fans";
37908777fb0SLewanczyk, Dawid                 } else if (sensorType == "voltage") {
38008777fb0SLewanczyk, Dawid                   fieldName = "Voltages";
38108777fb0SLewanczyk, Dawid                 } else if (sensorType == "current") {
38208777fb0SLewanczyk, Dawid                   fieldName = "PowerSupply";
38308777fb0SLewanczyk, Dawid                 } else if (sensorType == "power") {
38408777fb0SLewanczyk, Dawid                   fieldName = "PowerSupply";
38508777fb0SLewanczyk, Dawid                 } else {
38608777fb0SLewanczyk, Dawid                   CROW_LOG_ERROR << "Unsure how to handle sensorType "
38708777fb0SLewanczyk, Dawid                                  << sensorType;
38808777fb0SLewanczyk, Dawid                   continue;
38908777fb0SLewanczyk, Dawid                 }
39008777fb0SLewanczyk, Dawid 
39108777fb0SLewanczyk, Dawid                 nlohmann::json& temp_array =
39208777fb0SLewanczyk, Dawid                     asyncResp->res.json_value[fieldName];
39308777fb0SLewanczyk, Dawid 
39408777fb0SLewanczyk, Dawid                 // Create the array if it doesn't yet exist
39508777fb0SLewanczyk, Dawid                 if (temp_array.is_array() == false) {
39608777fb0SLewanczyk, Dawid                   temp_array = nlohmann::json::array();
39708777fb0SLewanczyk, Dawid                 }
39808777fb0SLewanczyk, Dawid 
39908777fb0SLewanczyk, Dawid                 temp_array.push_back(nlohmann::json::object());
40008777fb0SLewanczyk, Dawid                 nlohmann::json& sensor_json = temp_array.back();
40108777fb0SLewanczyk, Dawid                 sensor_json["@odata.id"] = "/redfish/v1/Chassis/" +
40208777fb0SLewanczyk, Dawid                                            asyncResp->chassisId + "/Thermal#/" +
40308777fb0SLewanczyk, Dawid                                            sensorName;
40408777fb0SLewanczyk, Dawid                 objectInterfacesToJson(sensorName, sensorType,
40508777fb0SLewanczyk, Dawid                                        objDictEntry.second, sensor_json);
40608777fb0SLewanczyk, Dawid               }
40708777fb0SLewanczyk, Dawid             };
40808777fb0SLewanczyk, Dawid 
40908777fb0SLewanczyk, Dawid             dbus::endpoint ep(connection, "/xyz/openbmc_project/Sensors",
41008777fb0SLewanczyk, Dawid                               "org.freedesktop.DBus.ObjectManager",
41108777fb0SLewanczyk, Dawid                               "GetManagedObjects");
41208777fb0SLewanczyk, Dawid             crow::connections::system_bus->async_method_call(
41308777fb0SLewanczyk, Dawid                 getManagedObjectsCb, ep);
41408777fb0SLewanczyk, Dawid           };
41508777fb0SLewanczyk, Dawid         };
41608777fb0SLewanczyk, Dawid     // Get connections and then pass it to get sensors
41708777fb0SLewanczyk, Dawid     getConnections(asyncResp, sensorNames, std::move(getConnectionCb));
41808777fb0SLewanczyk, Dawid   };
41908777fb0SLewanczyk, Dawid 
42008777fb0SLewanczyk, Dawid   // Get chassis information related to sensors
42108777fb0SLewanczyk, Dawid   getChassis(asyncResp, std::move(getChassisCb));
42208777fb0SLewanczyk, Dawid };
42308777fb0SLewanczyk, Dawid 
42408777fb0SLewanczyk, Dawid }  // namespace redfish
425