xref: /openbmc/bmcweb/features/redfish/lib/sensors.hpp (revision 55c7b7a2e58779580f33046d2dd8649243776700)
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 
2508777fb0SLewanczyk, Dawid namespace redfish {
2608777fb0SLewanczyk, Dawid 
2703b5bae3SJames Feist constexpr const char* DBUS_SENSOR_PREFIX = "/xyz/openbmc_project/sensors/";
2808777fb0SLewanczyk, Dawid 
2908777fb0SLewanczyk, Dawid using GetSubTreeType = std::vector<
3008777fb0SLewanczyk, Dawid     std::pair<std::string,
3108777fb0SLewanczyk, Dawid               std::vector<std::pair<std::string, std::vector<std::string>>>>>;
3208777fb0SLewanczyk, Dawid 
33aa2e59c1SEd Tanous using SensorVariant = sdbusplus::message::variant<int64_t, double>;
34aa2e59c1SEd Tanous 
3508777fb0SLewanczyk, Dawid using ManagedObjectsVectorType = std::vector<std::pair<
36aa2e59c1SEd Tanous     sdbusplus::message::object_path,
3708777fb0SLewanczyk, Dawid     boost::container::flat_map<
38aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>>>;
3908777fb0SLewanczyk, Dawid 
4008777fb0SLewanczyk, Dawid /**
41588c3f0dSKowalski, Kamil  * SensorsAsyncResp
4208777fb0SLewanczyk, Dawid  * Gathers data needed for response processing after async calls are done
4308777fb0SLewanczyk, Dawid  */
44588c3f0dSKowalski, Kamil class SensorsAsyncResp {
4508777fb0SLewanczyk, Dawid  public:
46*55c7b7a2SEd Tanous   SensorsAsyncResp(crow::Response& response, const std::string& chassisId,
4708777fb0SLewanczyk, Dawid                    const std::initializer_list<const char*> types)
48588c3f0dSKowalski, Kamil       : res(response), chassisId(chassisId), types(types) {
49*55c7b7a2SEd Tanous     res.jsonValue["@odata.id"] =
5008777fb0SLewanczyk, Dawid         "/redfish/v1/Chassis/" + chassisId + "/Thermal";
5108777fb0SLewanczyk, Dawid   }
5208777fb0SLewanczyk, Dawid 
53588c3f0dSKowalski, Kamil   ~SensorsAsyncResp() {
54e0d918bcSEd Tanous     if (res.result() == boost::beast::http::status::internal_server_error) {
5508777fb0SLewanczyk, Dawid       // Reset the json object to clear out any data that made it in before the
5608777fb0SLewanczyk, Dawid       // error happened
5708777fb0SLewanczyk, Dawid       // todo(ed) handle error condition with proper code
58*55c7b7a2SEd Tanous       res.jsonValue = nlohmann::json::object();
5908777fb0SLewanczyk, Dawid     }
6008777fb0SLewanczyk, Dawid     res.end();
6108777fb0SLewanczyk, Dawid   }
62588c3f0dSKowalski, Kamil 
6308777fb0SLewanczyk, Dawid   void setErrorStatus() {
64e0d918bcSEd Tanous     res.result(boost::beast::http::status::internal_server_error);
6508777fb0SLewanczyk, Dawid   }
6608777fb0SLewanczyk, Dawid 
67*55c7b7a2SEd Tanous   crow::Response& res;
68588c3f0dSKowalski, Kamil   std::string chassisId{};
6908777fb0SLewanczyk, Dawid   const std::vector<const char*> types;
7008777fb0SLewanczyk, Dawid };
7108777fb0SLewanczyk, Dawid 
7208777fb0SLewanczyk, Dawid /**
7308777fb0SLewanczyk, Dawid  * @brief Creates connections necessary for chassis sensors
74588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp 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>
79588c3f0dSKowalski, Kamil void getConnections(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
8008777fb0SLewanczyk, Dawid                     const boost::container::flat_set<std::string>& sensorNames,
8108777fb0SLewanczyk, Dawid                     Callback&& callback) {
82*55c7b7a2SEd Tanous   BMCWEB_LOG_DEBUG << "getConnections enter";
8303b5bae3SJames Feist   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 
8708777fb0SLewanczyk, Dawid   // Response handler for parsing objects subtree
88*55c7b7a2SEd Tanous   auto respHandler =
89588c3f0dSKowalski, Kamil       [ callback{std::move(callback)}, SensorsAsyncResp, sensorNames ](
9008777fb0SLewanczyk, Dawid           const boost::system::error_code ec, const GetSubTreeType& subtree) {
91*55c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getConnections resp_handler enter";
92e0d918bcSEd Tanous     if (ec) {
93588c3f0dSKowalski, Kamil       SensorsAsyncResp->setErrorStatus();
94*55c7b7a2SEd Tanous       BMCWEB_LOG_ERROR << "getConnections resp_handler: Dbus error " << ec;
9508777fb0SLewanczyk, Dawid       return;
9608777fb0SLewanczyk, Dawid     }
9708777fb0SLewanczyk, Dawid 
98*55c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
9908777fb0SLewanczyk, Dawid 
10008777fb0SLewanczyk, Dawid     // Make unique list of connections only for requested sensor types and
10108777fb0SLewanczyk, Dawid     // found in the chassis
10208777fb0SLewanczyk, Dawid     boost::container::flat_set<std::string> connections;
10308777fb0SLewanczyk, Dawid     // Intrinsic to avoid malloc.  Most systems will have < 8 sensor producers
10408777fb0SLewanczyk, Dawid     connections.reserve(8);
10508777fb0SLewanczyk, Dawid 
106*55c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames.size();
10708777fb0SLewanczyk, Dawid     for (const std::string& tsensor : sensorNames) {
108*55c7b7a2SEd Tanous       BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor;
10908777fb0SLewanczyk, Dawid     }
11008777fb0SLewanczyk, Dawid 
11108777fb0SLewanczyk, Dawid     for (const std::pair<
11208777fb0SLewanczyk, Dawid              std::string,
11308777fb0SLewanczyk, Dawid              std::vector<std::pair<std::string, std::vector<std::string>>>>&
11408777fb0SLewanczyk, Dawid              object : subtree) {
115588c3f0dSKowalski, Kamil       for (const char* type : SensorsAsyncResp->types) {
11608777fb0SLewanczyk, Dawid         if (boost::starts_with(object.first, type)) {
11708777fb0SLewanczyk, Dawid           auto lastPos = object.first.rfind('/');
11808777fb0SLewanczyk, Dawid           if (lastPos != std::string::npos) {
11908777fb0SLewanczyk, Dawid             std::string sensorName = object.first.substr(lastPos + 1);
12008777fb0SLewanczyk, Dawid 
12108777fb0SLewanczyk, Dawid             if (sensorNames.find(sensorName) != sensorNames.end()) {
122*55c7b7a2SEd Tanous               // For each Connection name
12308777fb0SLewanczyk, Dawid               for (const std::pair<std::string, std::vector<std::string>>&
12408777fb0SLewanczyk, Dawid                        objData : object.second) {
125*55c7b7a2SEd Tanous                 BMCWEB_LOG_DEBUG << "Adding connection: " << objData.first;
12608777fb0SLewanczyk, Dawid                 connections.insert(objData.first);
12708777fb0SLewanczyk, Dawid               }
12808777fb0SLewanczyk, Dawid             }
12908777fb0SLewanczyk, Dawid           }
13008777fb0SLewanczyk, Dawid           break;
13108777fb0SLewanczyk, Dawid         }
13208777fb0SLewanczyk, Dawid       }
13308777fb0SLewanczyk, Dawid     }
134*55c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections";
13508777fb0SLewanczyk, Dawid     callback(std::move(connections));
136*55c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getConnections resp_handler exit";
13708777fb0SLewanczyk, Dawid   };
13808777fb0SLewanczyk, Dawid 
13908777fb0SLewanczyk, Dawid   // Make call to ObjectMapper to find all sensors objects
140*55c7b7a2SEd Tanous   crow::connections::systemBus->async_method_call(
141*55c7b7a2SEd Tanous       std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
142aa2e59c1SEd Tanous       "/xyz/openbmc_project/object_mapper", "xyz.openbmc_project.ObjectMapper",
143aa2e59c1SEd Tanous       "GetSubTree", path, 2, interfaces);
144*55c7b7a2SEd Tanous   BMCWEB_LOG_DEBUG << "getConnections exit";
14508777fb0SLewanczyk, Dawid }
14608777fb0SLewanczyk, Dawid 
14708777fb0SLewanczyk, Dawid /**
14808777fb0SLewanczyk, Dawid  * @brief Retrieves requested chassis sensors and redundancy data from DBus .
149588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
15008777fb0SLewanczyk, Dawid  * @param callback  Callback for next step in gathered sensor processing
15108777fb0SLewanczyk, Dawid  */
15208777fb0SLewanczyk, Dawid template <typename Callback>
153588c3f0dSKowalski, Kamil void getChassis(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
154588c3f0dSKowalski, Kamil                 Callback&& callback) {
155*55c7b7a2SEd Tanous   BMCWEB_LOG_DEBUG << "getChassis enter";
15608777fb0SLewanczyk, Dawid   // Process response from EntityManager and extract chassis data
157*55c7b7a2SEd Tanous   auto respHandler = [ callback{std::move(callback)}, SensorsAsyncResp ](
15808777fb0SLewanczyk, Dawid       const boost::system::error_code ec, ManagedObjectsVectorType& resp) {
159*55c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis respHandler enter";
16008777fb0SLewanczyk, Dawid     if (ec) {
161*55c7b7a2SEd Tanous       BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec;
162588c3f0dSKowalski, Kamil       SensorsAsyncResp->setErrorStatus();
16308777fb0SLewanczyk, Dawid       return;
16408777fb0SLewanczyk, Dawid     }
16508777fb0SLewanczyk, Dawid     boost::container::flat_set<std::string> sensorNames;
16608777fb0SLewanczyk, Dawid 
167588c3f0dSKowalski, Kamil     //   SensorsAsyncResp->chassisId
168daf36e2eSEd Tanous     bool foundChassis = false;
169daf36e2eSEd Tanous     std::vector<std::string> split;
170daf36e2eSEd Tanous     // Reserve space for
171daf36e2eSEd Tanous     // /xyz/openbmc_project/inventory/<name>/<subname> + 3 subnames
172daf36e2eSEd Tanous     split.reserve(8);
173daf36e2eSEd Tanous 
174daf36e2eSEd Tanous     for (const auto& objDictEntry : resp) {
175daf36e2eSEd Tanous       const std::string& objectPath =
176daf36e2eSEd Tanous           static_cast<const std::string&>(objDictEntry.first);
177daf36e2eSEd Tanous       boost::algorithm::split(split, objectPath, boost::is_any_of("/"));
178daf36e2eSEd Tanous       if (split.size() < 2) {
179*55c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Got path that isn't long enough " << objectPath;
180daf36e2eSEd Tanous         split.clear();
181daf36e2eSEd Tanous         continue;
182daf36e2eSEd Tanous       }
183daf36e2eSEd Tanous       const std::string& sensorName = split.end()[-1];
184daf36e2eSEd Tanous       const std::string& chassisName = split.end()[-2];
185daf36e2eSEd Tanous 
186588c3f0dSKowalski, Kamil       if (chassisName != SensorsAsyncResp->chassisId) {
187daf36e2eSEd Tanous         split.clear();
188daf36e2eSEd Tanous         continue;
189daf36e2eSEd Tanous       }
190*55c7b7a2SEd Tanous       BMCWEB_LOG_DEBUG << "New sensor: " << sensorName;
191daf36e2eSEd Tanous       foundChassis = true;
19208777fb0SLewanczyk, Dawid       sensorNames.emplace(sensorName);
193daf36e2eSEd Tanous       split.clear();
19408777fb0SLewanczyk, Dawid     };
195*55c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "Found " << sensorNames.size() << " Sensor names";
19608777fb0SLewanczyk, Dawid 
19708777fb0SLewanczyk, Dawid     if (!foundChassis) {
198*55c7b7a2SEd Tanous       BMCWEB_LOG_INFO << "Unable to find chassis named "
199588c3f0dSKowalski, Kamil                       << SensorsAsyncResp->chassisId;
200588c3f0dSKowalski, Kamil       SensorsAsyncResp->res.result(boost::beast::http::status::not_found);
20108777fb0SLewanczyk, Dawid     } else {
20208777fb0SLewanczyk, Dawid       callback(sensorNames);
20308777fb0SLewanczyk, Dawid     }
204*55c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis respHandler exit";
20508777fb0SLewanczyk, Dawid   };
20608777fb0SLewanczyk, Dawid 
20708777fb0SLewanczyk, Dawid   // Make call to EntityManager to find all chassis objects
208*55c7b7a2SEd Tanous   crow::connections::systemBus->async_method_call(
209*55c7b7a2SEd Tanous       respHandler, "xyz.openbmc_project.EntityManager", "/",
2107885954aSLewanczyk, Dawid       "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
211*55c7b7a2SEd Tanous   BMCWEB_LOG_DEBUG << "getChassis exit";
21208777fb0SLewanczyk, Dawid }
21308777fb0SLewanczyk, Dawid 
21408777fb0SLewanczyk, Dawid /**
21508777fb0SLewanczyk, Dawid  * @brief Builds a json sensor representation of a sensor.
21608777fb0SLewanczyk, Dawid  * @param sensorName  The name of the sensor to be built
217274fad5aSGunnar Mills  * @param sensorType  The type (temperature, fan_tach, etc) of the sensor to
21808777fb0SLewanczyk, Dawid  * build
21908777fb0SLewanczyk, Dawid  * @param interfacesDict  A dictionary of the interfaces and properties of said
22008777fb0SLewanczyk, Dawid  * interfaces to be built from
22108777fb0SLewanczyk, Dawid  * @param sensor_json  The json object to fill
22208777fb0SLewanczyk, Dawid  */
22308777fb0SLewanczyk, Dawid void objectInterfacesToJson(
22408777fb0SLewanczyk, Dawid     const std::string& sensorName, const std::string& sensorType,
22508777fb0SLewanczyk, Dawid     const boost::container::flat_map<
226aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>&
22708777fb0SLewanczyk, Dawid         interfacesDict,
22808777fb0SLewanczyk, Dawid     nlohmann::json& sensor_json) {
22908777fb0SLewanczyk, Dawid   // We need a value interface before we can do anything with it
230*55c7b7a2SEd Tanous   auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
231*55c7b7a2SEd Tanous   if (valueIt == interfacesDict.end()) {
232*55c7b7a2SEd Tanous     BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface";
23308777fb0SLewanczyk, Dawid     return;
23408777fb0SLewanczyk, Dawid   }
23508777fb0SLewanczyk, Dawid 
23608777fb0SLewanczyk, Dawid   // Assume values exist as is (10^0 == 1) if no scale exists
23708777fb0SLewanczyk, Dawid   int64_t scaleMultiplier = 0;
23808777fb0SLewanczyk, Dawid 
239*55c7b7a2SEd Tanous   auto scaleIt = valueIt->second.find("Scale");
24008777fb0SLewanczyk, Dawid   // If a scale exists, pull value as int64, and use the scaling.
241*55c7b7a2SEd Tanous   if (scaleIt != valueIt->second.end()) {
242*55c7b7a2SEd Tanous     const int64_t* int64Value = mapbox::getPtr<const int64_t>(scaleIt->second);
24308777fb0SLewanczyk, Dawid     if (int64Value != nullptr) {
24408777fb0SLewanczyk, Dawid       scaleMultiplier = *int64Value;
24508777fb0SLewanczyk, Dawid     }
24608777fb0SLewanczyk, Dawid   }
24708777fb0SLewanczyk, Dawid 
24808777fb0SLewanczyk, Dawid   sensor_json["MemberId"] = sensorName;
24908777fb0SLewanczyk, Dawid   sensor_json["Name"] = sensorName;
25008777fb0SLewanczyk, Dawid   sensor_json["Status"]["State"] = "Enabled";
25108777fb0SLewanczyk, Dawid   sensor_json["Status"]["Health"] = "OK";
25208777fb0SLewanczyk, Dawid 
25308777fb0SLewanczyk, Dawid   // Parameter to set to override the type we get from dbus, and force it to
25408777fb0SLewanczyk, Dawid   // int, regardless of what is available.  This is used for schemas like fan,
25508777fb0SLewanczyk, Dawid   // that require integers, not floats.
25608777fb0SLewanczyk, Dawid   bool forceToInt = false;
25708777fb0SLewanczyk, Dawid 
25808777fb0SLewanczyk, Dawid   const char* unit = "Reading";
25908777fb0SLewanczyk, Dawid   if (sensorType == "temperature") {
26008777fb0SLewanczyk, Dawid     unit = "ReadingCelsius";
2617885954aSLewanczyk, Dawid     sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature";
26208777fb0SLewanczyk, Dawid     // TODO(ed) Documentation says that path should be type fan_tach,
26308777fb0SLewanczyk, Dawid     // implementation seems to implement fan
26403b5bae3SJames Feist   } else if (sensorType == "fan" || sensorType == "fan_tach") {
26508777fb0SLewanczyk, Dawid     unit = "Reading";
26608777fb0SLewanczyk, Dawid     sensor_json["ReadingUnits"] = "RPM";
2677885954aSLewanczyk, Dawid     sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
26808777fb0SLewanczyk, Dawid     forceToInt = true;
26908777fb0SLewanczyk, Dawid   } else if (sensorType == "voltage") {
27008777fb0SLewanczyk, Dawid     unit = "ReadingVolts";
2717885954aSLewanczyk, Dawid     sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage";
27208777fb0SLewanczyk, Dawid   } else {
273*55c7b7a2SEd Tanous     BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
27408777fb0SLewanczyk, Dawid     return;
27508777fb0SLewanczyk, Dawid   }
27608777fb0SLewanczyk, Dawid   // Map of dbus interface name, dbus property name and redfish property_name
27708777fb0SLewanczyk, Dawid   std::vector<std::tuple<const char*, const char*, const char*>> properties;
27808777fb0SLewanczyk, Dawid   properties.reserve(7);
27908777fb0SLewanczyk, Dawid 
28008777fb0SLewanczyk, Dawid   properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
28108777fb0SLewanczyk, Dawid   properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
28208777fb0SLewanczyk, Dawid                           "WarningHigh", "UpperThresholdNonCritical");
28308777fb0SLewanczyk, Dawid   properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
28408777fb0SLewanczyk, Dawid                           "WarningLow", "LowerThresholdNonCritical");
28508777fb0SLewanczyk, Dawid   properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
28608777fb0SLewanczyk, Dawid                           "CriticalHigh", "UpperThresholdCritical");
28708777fb0SLewanczyk, Dawid   properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
28808777fb0SLewanczyk, Dawid                           "CriticalLow", "LowerThresholdCritical");
28908777fb0SLewanczyk, Dawid 
29008777fb0SLewanczyk, Dawid   if (sensorType == "temperature") {
29108777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
29208777fb0SLewanczyk, Dawid                             "MinReadingRangeTemp");
29308777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
29408777fb0SLewanczyk, Dawid                             "MaxReadingRangeTemp");
29508777fb0SLewanczyk, Dawid   } else {
29608777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
29708777fb0SLewanczyk, Dawid                             "MinReadingRange");
29808777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
29908777fb0SLewanczyk, Dawid                             "MaxReadingRange");
30008777fb0SLewanczyk, Dawid   }
30108777fb0SLewanczyk, Dawid 
30208777fb0SLewanczyk, Dawid   for (const std::tuple<const char*, const char*, const char*>& p :
30308777fb0SLewanczyk, Dawid        properties) {
30408777fb0SLewanczyk, Dawid     auto interfaceProperties = interfacesDict.find(std::get<0>(p));
30508777fb0SLewanczyk, Dawid     if (interfaceProperties != interfacesDict.end()) {
306*55c7b7a2SEd Tanous       auto valueIt = interfaceProperties->second.find(std::get<1>(p));
307*55c7b7a2SEd Tanous       if (valueIt != interfaceProperties->second.end()) {
308*55c7b7a2SEd Tanous         const SensorVariant& valueVariant = valueIt->second;
309*55c7b7a2SEd Tanous         nlohmann::json& valueIt = sensor_json[std::get<2>(p)];
310aa2e59c1SEd Tanous 
31108777fb0SLewanczyk, Dawid         // Attempt to pull the int64 directly
312*55c7b7a2SEd Tanous         const int64_t* int64Value = mapbox::getPtr<const int64_t>(valueVariant);
31308777fb0SLewanczyk, Dawid 
31408777fb0SLewanczyk, Dawid         if (int64Value != nullptr) {
31508777fb0SLewanczyk, Dawid           if (forceToInt || scaleMultiplier >= 0) {
316*55c7b7a2SEd Tanous             valueIt = *int64Value * std::pow(10, scaleMultiplier);
31708777fb0SLewanczyk, Dawid           } else {
318*55c7b7a2SEd Tanous             valueIt = *int64Value *
31908777fb0SLewanczyk, Dawid                       std::pow(10, static_cast<double>(scaleMultiplier));
32008777fb0SLewanczyk, Dawid           }
32108777fb0SLewanczyk, Dawid         }
32208777fb0SLewanczyk, Dawid         // Attempt to pull the float directly
323*55c7b7a2SEd Tanous         const double* doubleValue = mapbox::getPtr<const double>(valueVariant);
32408777fb0SLewanczyk, Dawid 
32508777fb0SLewanczyk, Dawid         if (doubleValue != nullptr) {
32608777fb0SLewanczyk, Dawid           if (!forceToInt) {
327*55c7b7a2SEd Tanous             valueIt = *doubleValue *
32808777fb0SLewanczyk, Dawid                       std::pow(10, static_cast<double>(scaleMultiplier));
32908777fb0SLewanczyk, Dawid           } else {
330*55c7b7a2SEd Tanous             valueIt = static_cast<int64_t>(*doubleValue *
33108777fb0SLewanczyk, Dawid                                            std::pow(10, scaleMultiplier));
33208777fb0SLewanczyk, Dawid           }
33308777fb0SLewanczyk, Dawid         }
33408777fb0SLewanczyk, Dawid       }
33508777fb0SLewanczyk, Dawid     }
33608777fb0SLewanczyk, Dawid   }
337*55c7b7a2SEd Tanous   BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
33808777fb0SLewanczyk, Dawid }
33908777fb0SLewanczyk, Dawid 
34008777fb0SLewanczyk, Dawid /**
34108777fb0SLewanczyk, Dawid  * @brief Entry point for retrieving sensors data related to requested
34208777fb0SLewanczyk, Dawid  *        chassis.
343588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
34408777fb0SLewanczyk, Dawid  */
345588c3f0dSKowalski, Kamil void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp) {
346*55c7b7a2SEd Tanous   BMCWEB_LOG_DEBUG << "getChassisData enter";
347588c3f0dSKowalski, Kamil   auto getChassisCb = [&, SensorsAsyncResp](
348588c3f0dSKowalski, Kamil                           boost::container::flat_set<std::string>&
34908777fb0SLewanczyk, Dawid                               sensorNames) {
350*55c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisCb enter";
351588c3f0dSKowalski, Kamil     auto getConnectionCb =
352588c3f0dSKowalski, Kamil         [&, SensorsAsyncResp, sensorNames](
353588c3f0dSKowalski, Kamil             const boost::container::flat_set<std::string>& connections) {
354*55c7b7a2SEd Tanous           BMCWEB_LOG_DEBUG << "getConnectionCb enter";
35508777fb0SLewanczyk, Dawid           // Get managed objects from all services exposing sensors
35608777fb0SLewanczyk, Dawid           for (const std::string& connection : connections) {
35708777fb0SLewanczyk, Dawid             // Response handler to process managed objects
358588c3f0dSKowalski, Kamil             auto getManagedObjectsCb = [&, SensorsAsyncResp, sensorNames](
35908777fb0SLewanczyk, Dawid                                            const boost::system::error_code ec,
36008777fb0SLewanczyk, Dawid                                            ManagedObjectsVectorType& resp) {
361*55c7b7a2SEd Tanous               BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
3627885954aSLewanczyk, Dawid               if (ec) {
363*55c7b7a2SEd Tanous                 BMCWEB_LOG_ERROR << "getManagedObjectsCb DBUS error: " << ec;
3647885954aSLewanczyk, Dawid                 SensorsAsyncResp->setErrorStatus();
3657885954aSLewanczyk, Dawid                 return;
3667885954aSLewanczyk, Dawid               }
36708777fb0SLewanczyk, Dawid               // Go through all objects and update response with
36808777fb0SLewanczyk, Dawid               // sensor data
36908777fb0SLewanczyk, Dawid               for (const auto& objDictEntry : resp) {
370aa2e59c1SEd Tanous                 const std::string& objPath =
371daf36e2eSEd Tanous                     static_cast<const std::string&>(objDictEntry.first);
372*55c7b7a2SEd Tanous                 BMCWEB_LOG_DEBUG << "getManagedObjectsCb parsing object "
373588c3f0dSKowalski, Kamil                                  << objPath;
374e0d918bcSEd Tanous 
37508777fb0SLewanczyk, Dawid                 std::vector<std::string> split;
37608777fb0SLewanczyk, Dawid                 // Reserve space for
37703b5bae3SJames Feist                 // /xyz/openbmc_project/sensors/<name>/<subname>
37808777fb0SLewanczyk, Dawid                 split.reserve(6);
37908777fb0SLewanczyk, Dawid                 boost::algorithm::split(split, objPath, boost::is_any_of("/"));
38008777fb0SLewanczyk, Dawid                 if (split.size() < 6) {
381*55c7b7a2SEd Tanous                   BMCWEB_LOG_ERROR << "Got path that isn't long enough "
382588c3f0dSKowalski, Kamil                                    << objPath;
38308777fb0SLewanczyk, Dawid                   continue;
38408777fb0SLewanczyk, Dawid                 }
38508777fb0SLewanczyk, Dawid                 // These indexes aren't intuitive, as boost::split puts an empty
386e0d918bcSEd Tanous                 // string at the beggining
38708777fb0SLewanczyk, Dawid                 const std::string& sensorType = split[4];
38808777fb0SLewanczyk, Dawid                 const std::string& sensorName = split[5];
389*55c7b7a2SEd Tanous                 BMCWEB_LOG_DEBUG << "sensorName " << sensorName
390*55c7b7a2SEd Tanous                                  << " sensorType " << sensorType;
39108777fb0SLewanczyk, Dawid                 if (sensorNames.find(sensorName) == sensorNames.end()) {
392*55c7b7a2SEd Tanous                   BMCWEB_LOG_ERROR << sensorName << " not in sensor list ";
39308777fb0SLewanczyk, Dawid                   continue;
39408777fb0SLewanczyk, Dawid                 }
39508777fb0SLewanczyk, Dawid 
39608777fb0SLewanczyk, Dawid                 const char* fieldName = nullptr;
39708777fb0SLewanczyk, Dawid                 if (sensorType == "temperature") {
39808777fb0SLewanczyk, Dawid                   fieldName = "Temperatures";
39908777fb0SLewanczyk, Dawid                 } else if (sensorType == "fan" || sensorType == "fan_tach") {
40008777fb0SLewanczyk, Dawid                   fieldName = "Fans";
40108777fb0SLewanczyk, Dawid                 } else if (sensorType == "voltage") {
40208777fb0SLewanczyk, Dawid                   fieldName = "Voltages";
40308777fb0SLewanczyk, Dawid                 } else if (sensorType == "current") {
40408777fb0SLewanczyk, Dawid                   fieldName = "PowerSupply";
40508777fb0SLewanczyk, Dawid                 } else if (sensorType == "power") {
40608777fb0SLewanczyk, Dawid                   fieldName = "PowerSupply";
40708777fb0SLewanczyk, Dawid                 } else {
408*55c7b7a2SEd Tanous                   BMCWEB_LOG_ERROR << "Unsure how to handle sensorType "
40908777fb0SLewanczyk, Dawid                                    << sensorType;
41008777fb0SLewanczyk, Dawid                   continue;
41108777fb0SLewanczyk, Dawid                 }
41208777fb0SLewanczyk, Dawid 
413*55c7b7a2SEd Tanous                 nlohmann::json& tempArray =
414*55c7b7a2SEd Tanous                     SensorsAsyncResp->res.jsonValue[fieldName];
41508777fb0SLewanczyk, Dawid 
41608777fb0SLewanczyk, Dawid                 // Create the array if it doesn't yet exist
417*55c7b7a2SEd Tanous                 if (tempArray.is_array() == false) {
418*55c7b7a2SEd Tanous                   tempArray = nlohmann::json::array();
41908777fb0SLewanczyk, Dawid                 }
42008777fb0SLewanczyk, Dawid 
421*55c7b7a2SEd Tanous                 tempArray.push_back(
422588c3f0dSKowalski, Kamil                     {{"@odata.id", "/redfish/v1/Chassis/" +
423588c3f0dSKowalski, Kamil                                        SensorsAsyncResp->chassisId +
424e0d918bcSEd Tanous                                        "/Thermal#/" + sensorName}});
425*55c7b7a2SEd Tanous                 nlohmann::json& sensorJson = tempArray.back();
426588c3f0dSKowalski, Kamil                 objectInterfacesToJson(sensorName, sensorType,
427*55c7b7a2SEd Tanous                                        objDictEntry.second, sensorJson);
42808777fb0SLewanczyk, Dawid               }
429*55c7b7a2SEd Tanous               BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
43008777fb0SLewanczyk, Dawid             };
431*55c7b7a2SEd Tanous             crow::connections::systemBus->async_method_call(
4327885954aSLewanczyk, Dawid                 getManagedObjectsCb, connection, "/",
433aa2e59c1SEd Tanous                 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
43408777fb0SLewanczyk, Dawid           };
435*55c7b7a2SEd Tanous           BMCWEB_LOG_DEBUG << "getConnectionCb exit";
43608777fb0SLewanczyk, Dawid         };
437*55c7b7a2SEd Tanous     // get connections and then pass it to get sensors
438588c3f0dSKowalski, Kamil     getConnections(SensorsAsyncResp, sensorNames, std::move(getConnectionCb));
439*55c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisCb exit";
44008777fb0SLewanczyk, Dawid   };
44108777fb0SLewanczyk, Dawid 
442*55c7b7a2SEd Tanous   // get chassis information related to sensors
443588c3f0dSKowalski, Kamil   getChassis(SensorsAsyncResp, std::move(getChassisCb));
444*55c7b7a2SEd Tanous   BMCWEB_LOG_DEBUG << "getChassisData exit";
44508777fb0SLewanczyk, Dawid };
44608777fb0SLewanczyk, Dawid 
44708777fb0SLewanczyk, Dawid }  // namespace redfish
448