xref: /openbmc/bmcweb/features/redfish/lib/sensors.hpp (revision 08777fb0eca7e0c3f52aeb829a9b8f4fa0bbdb73)
1*08777fb0SLewanczyk, Dawid /*
2*08777fb0SLewanczyk, Dawid // Copyright (c) 2018 Intel Corporation
3*08777fb0SLewanczyk, Dawid //
4*08777fb0SLewanczyk, Dawid // Licensed under the Apache License, Version 2.0 (the "License");
5*08777fb0SLewanczyk, Dawid // you may not use this file except in compliance with the License.
6*08777fb0SLewanczyk, Dawid // You may obtain a copy of the License at
7*08777fb0SLewanczyk, Dawid //
8*08777fb0SLewanczyk, Dawid //      http://www.apache.org/licenses/LICENSE-2.0
9*08777fb0SLewanczyk, Dawid //
10*08777fb0SLewanczyk, Dawid // Unless required by applicable law or agreed to in writing, software
11*08777fb0SLewanczyk, Dawid // distributed under the License is distributed on an "AS IS" BASIS,
12*08777fb0SLewanczyk, Dawid // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*08777fb0SLewanczyk, Dawid // See the License for the specific language governing permissions and
14*08777fb0SLewanczyk, Dawid // limitations under the License.
15*08777fb0SLewanczyk, Dawid */
16*08777fb0SLewanczyk, Dawid #pragma once
17*08777fb0SLewanczyk, Dawid 
18*08777fb0SLewanczyk, Dawid #include <math.h>
19*08777fb0SLewanczyk, Dawid #include <dbus_singleton.hpp>
20*08777fb0SLewanczyk, Dawid #include <boost/algorithm/string/predicate.hpp>
21*08777fb0SLewanczyk, Dawid #include <boost/algorithm/string/split.hpp>
22*08777fb0SLewanczyk, Dawid #include <boost/container/flat_map.hpp>
23*08777fb0SLewanczyk, Dawid #include <boost/range/algorithm/replace_copy_if.hpp>
24*08777fb0SLewanczyk, Dawid #include <boost/variant.hpp>
25*08777fb0SLewanczyk, Dawid #include <boost/variant/get.hpp>
26*08777fb0SLewanczyk, Dawid 
27*08777fb0SLewanczyk, Dawid namespace redfish {
28*08777fb0SLewanczyk, Dawid 
29*08777fb0SLewanczyk, Dawid constexpr const char* DBUS_SENSOR_PREFIX = "/xyz/openbmc_project/Sensors/";
30*08777fb0SLewanczyk, Dawid 
31*08777fb0SLewanczyk, Dawid using GetSubTreeType = std::vector<
32*08777fb0SLewanczyk, Dawid     std::pair<std::string,
33*08777fb0SLewanczyk, Dawid               std::vector<std::pair<std::string, std::vector<std::string>>>>>;
34*08777fb0SLewanczyk, Dawid 
35*08777fb0SLewanczyk, Dawid using ManagedObjectsVectorType = std::vector<std::pair<
36*08777fb0SLewanczyk, Dawid     dbus::object_path,
37*08777fb0SLewanczyk, Dawid     boost::container::flat_map<
38*08777fb0SLewanczyk, Dawid         std::string,
39*08777fb0SLewanczyk, Dawid         boost::container::flat_map<dbus::string, dbus::dbus_variant>>>>;
40*08777fb0SLewanczyk, Dawid 
41*08777fb0SLewanczyk, Dawid /**
42*08777fb0SLewanczyk, Dawid  * AsyncResp
43*08777fb0SLewanczyk, Dawid  * Gathers data needed for response processing after async calls are done
44*08777fb0SLewanczyk, Dawid  */
45*08777fb0SLewanczyk, Dawid class AsyncResp {
46*08777fb0SLewanczyk, Dawid  public:
47*08777fb0SLewanczyk, Dawid   AsyncResp(crow::response& response, const std::string& chassisId,
48*08777fb0SLewanczyk, Dawid             const std::initializer_list<const char*> types)
49*08777fb0SLewanczyk, Dawid       : chassisId(chassisId), res(response), types(types) {
50*08777fb0SLewanczyk, Dawid     res.json_value["@odata.id"] =
51*08777fb0SLewanczyk, Dawid         "/redfish/v1/Chassis/" + chassisId + "/Thermal";
52*08777fb0SLewanczyk, Dawid   }
53*08777fb0SLewanczyk, Dawid 
54*08777fb0SLewanczyk, Dawid   ~AsyncResp() {
55*08777fb0SLewanczyk, Dawid     if (res.code != static_cast<int>(HttpRespCode::OK)) {
56*08777fb0SLewanczyk, Dawid       // Reset the json object to clear out any data that made it in before the
57*08777fb0SLewanczyk, Dawid       // error happened
58*08777fb0SLewanczyk, Dawid       // todo(ed) handle error condition with proper code
59*08777fb0SLewanczyk, Dawid       res.json_value = nlohmann::json::object();
60*08777fb0SLewanczyk, Dawid     }
61*08777fb0SLewanczyk, Dawid     res.end();
62*08777fb0SLewanczyk, Dawid   }
63*08777fb0SLewanczyk, Dawid   void setErrorStatus() {
64*08777fb0SLewanczyk, Dawid     res.code = static_cast<int>(HttpRespCode::INTERNAL_ERROR);
65*08777fb0SLewanczyk, Dawid   }
66*08777fb0SLewanczyk, Dawid 
67*08777fb0SLewanczyk, Dawid   std::string chassisId{};
68*08777fb0SLewanczyk, Dawid   crow::response& res;
69*08777fb0SLewanczyk, Dawid   const std::vector<const char*> types;
70*08777fb0SLewanczyk, Dawid };
71*08777fb0SLewanczyk, Dawid 
72*08777fb0SLewanczyk, Dawid /**
73*08777fb0SLewanczyk, Dawid  * @brief Creates connections necessary for chassis sensors
74*08777fb0SLewanczyk, Dawid  * @param asyncResp Pointer to object holding response data
75*08777fb0SLewanczyk, Dawid  * @param sensorNames Sensors retrieved from chassis
76*08777fb0SLewanczyk, Dawid  * @param callback Callback for processing gathered connections
77*08777fb0SLewanczyk, Dawid  */
78*08777fb0SLewanczyk, Dawid template <typename Callback>
79*08777fb0SLewanczyk, Dawid void getConnections(const std::shared_ptr<AsyncResp>& asyncResp,
80*08777fb0SLewanczyk, Dawid                     const boost::container::flat_set<std::string>& sensorNames,
81*08777fb0SLewanczyk, Dawid                     Callback&& callback) {
82*08777fb0SLewanczyk, Dawid   CROW_LOG_DEBUG << "getConnections";
83*08777fb0SLewanczyk, Dawid   const std::string path = "/xyz/openbmc_project/Sensors";
84*08777fb0SLewanczyk, Dawid   const std::array<std::string, 1> interfaces = {
85*08777fb0SLewanczyk, Dawid       "xyz.openbmc_project.Sensor.Value"};
86*08777fb0SLewanczyk, Dawid   const dbus::endpoint object_mapper(
87*08777fb0SLewanczyk, Dawid       "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper",
88*08777fb0SLewanczyk, Dawid       "xyz.openbmc_project.ObjectMapper", "GetSubTree");
89*08777fb0SLewanczyk, Dawid 
90*08777fb0SLewanczyk, Dawid   // Response handler for parsing objects subtree
91*08777fb0SLewanczyk, Dawid   auto resp_handler = [ callback{std::move(callback)}, asyncResp, sensorNames ](
92*08777fb0SLewanczyk, Dawid       const boost::system::error_code ec, const GetSubTreeType& subtree) {
93*08777fb0SLewanczyk, Dawid     if (ec != 0) {
94*08777fb0SLewanczyk, Dawid       asyncResp->setErrorStatus();
95*08777fb0SLewanczyk, Dawid       CROW_LOG_ERROR << "Dbus error " << ec;
96*08777fb0SLewanczyk, Dawid       return;
97*08777fb0SLewanczyk, Dawid     }
98*08777fb0SLewanczyk, Dawid 
99*08777fb0SLewanczyk, Dawid     CROW_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
100*08777fb0SLewanczyk, Dawid 
101*08777fb0SLewanczyk, Dawid     // Make unique list of connections only for requested sensor types and
102*08777fb0SLewanczyk, Dawid     // found in the chassis
103*08777fb0SLewanczyk, Dawid     boost::container::flat_set<std::string> connections;
104*08777fb0SLewanczyk, Dawid     // Intrinsic to avoid malloc.  Most systems will have < 8 sensor producers
105*08777fb0SLewanczyk, Dawid     connections.reserve(8);
106*08777fb0SLewanczyk, Dawid 
107*08777fb0SLewanczyk, Dawid     CROW_LOG_DEBUG << "sensorNames list cout: " << sensorNames.size();
108*08777fb0SLewanczyk, Dawid     for (const std::string& tsensor : sensorNames) {
109*08777fb0SLewanczyk, Dawid       CROW_LOG_DEBUG << "Sensor to find: " << tsensor;
110*08777fb0SLewanczyk, Dawid     }
111*08777fb0SLewanczyk, Dawid 
112*08777fb0SLewanczyk, Dawid     for (const std::pair<
113*08777fb0SLewanczyk, Dawid              std::string,
114*08777fb0SLewanczyk, Dawid              std::vector<std::pair<std::string, std::vector<std::string>>>>&
115*08777fb0SLewanczyk, Dawid              object : subtree) {
116*08777fb0SLewanczyk, Dawid       for (const char* type : asyncResp->types) {
117*08777fb0SLewanczyk, Dawid         if (boost::starts_with(object.first, type)) {
118*08777fb0SLewanczyk, Dawid           auto lastPos = object.first.rfind('/');
119*08777fb0SLewanczyk, Dawid           if (lastPos != std::string::npos) {
120*08777fb0SLewanczyk, Dawid             std::string sensorName = object.first.substr(lastPos + 1);
121*08777fb0SLewanczyk, Dawid 
122*08777fb0SLewanczyk, Dawid             if (sensorNames.find(sensorName) != sensorNames.end()) {
123*08777fb0SLewanczyk, Dawid               // For each connection name
124*08777fb0SLewanczyk, Dawid               for (const std::pair<std::string, std::vector<std::string>>&
125*08777fb0SLewanczyk, Dawid                        objData : object.second) {
126*08777fb0SLewanczyk, Dawid                 connections.insert(objData.first);
127*08777fb0SLewanczyk, Dawid               }
128*08777fb0SLewanczyk, Dawid             }
129*08777fb0SLewanczyk, Dawid           }
130*08777fb0SLewanczyk, Dawid           break;
131*08777fb0SLewanczyk, Dawid         }
132*08777fb0SLewanczyk, Dawid       }
133*08777fb0SLewanczyk, Dawid     }
134*08777fb0SLewanczyk, Dawid     CROW_LOG_DEBUG << "Found " << connections.size() << " connections";
135*08777fb0SLewanczyk, Dawid     callback(std::move(connections));
136*08777fb0SLewanczyk, Dawid   };
137*08777fb0SLewanczyk, Dawid 
138*08777fb0SLewanczyk, Dawid   // Make call to ObjectMapper to find all sensors objects
139*08777fb0SLewanczyk, Dawid   crow::connections::system_bus->async_method_call(resp_handler, object_mapper,
140*08777fb0SLewanczyk, Dawid                                                    path, 2, interfaces);
141*08777fb0SLewanczyk, Dawid }
142*08777fb0SLewanczyk, Dawid 
143*08777fb0SLewanczyk, Dawid /**
144*08777fb0SLewanczyk, Dawid  * @brief Retrieves requested chassis sensors and redundancy data from DBus .
145*08777fb0SLewanczyk, Dawid  * @param asyncResp   Pointer to object holding response data
146*08777fb0SLewanczyk, Dawid  * @param callback  Callback for next step in gathered sensor processing
147*08777fb0SLewanczyk, Dawid  */
148*08777fb0SLewanczyk, Dawid template <typename Callback>
149*08777fb0SLewanczyk, Dawid void getChassis(const std::shared_ptr<AsyncResp>& asyncResp,
150*08777fb0SLewanczyk, Dawid                 Callback&& callback) {
151*08777fb0SLewanczyk, Dawid   CROW_LOG_DEBUG << "getChassis Done";
152*08777fb0SLewanczyk, Dawid   const dbus::endpoint entityManager = {
153*08777fb0SLewanczyk, Dawid       "xyz.openbmc_project.EntityManager",
154*08777fb0SLewanczyk, Dawid       "/xyz/openbmc_project/Inventory/Item/Chassis",
155*08777fb0SLewanczyk, Dawid       "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"};
156*08777fb0SLewanczyk, Dawid 
157*08777fb0SLewanczyk, Dawid   // Process response from EntityManager and extract chassis data
158*08777fb0SLewanczyk, Dawid   auto resp_handler = [ callback{std::move(callback)}, asyncResp ](
159*08777fb0SLewanczyk, Dawid       const boost::system::error_code ec, ManagedObjectsVectorType& resp) {
160*08777fb0SLewanczyk, Dawid     CROW_LOG_DEBUG << "getChassis resp_handler called back Done";
161*08777fb0SLewanczyk, Dawid     if (ec) {
162*08777fb0SLewanczyk, Dawid       CROW_LOG_ERROR << "getChassis resp_handler got error " << ec;
163*08777fb0SLewanczyk, Dawid       asyncResp->setErrorStatus();
164*08777fb0SLewanczyk, Dawid       return;
165*08777fb0SLewanczyk, Dawid     }
166*08777fb0SLewanczyk, Dawid     boost::container::flat_set<std::string> sensorNames;
167*08777fb0SLewanczyk, Dawid     const std::string chassis_prefix =
168*08777fb0SLewanczyk, Dawid         "/xyz/openbmc_project/Inventory/Item/Chassis/" + asyncResp->chassisId +
169*08777fb0SLewanczyk, Dawid         '/';
170*08777fb0SLewanczyk, Dawid     CROW_LOG_DEBUG << "Chassis Prefix " << chassis_prefix;
171*08777fb0SLewanczyk, Dawid     bool foundChassis = false;
172*08777fb0SLewanczyk, Dawid     for (const auto& objDictEntry : resp) {
173*08777fb0SLewanczyk, Dawid       if (boost::starts_with(objDictEntry.first.value, chassis_prefix)) {
174*08777fb0SLewanczyk, Dawid         foundChassis = true;
175*08777fb0SLewanczyk, Dawid         const std::string sensorName =
176*08777fb0SLewanczyk, Dawid             objDictEntry.first.value.substr(chassis_prefix.size());
177*08777fb0SLewanczyk, Dawid         // Make sure this isn't a subobject (like a threshold)
178*08777fb0SLewanczyk, Dawid         const std::size_t sensorPos = sensorName.find('/');
179*08777fb0SLewanczyk, Dawid         if (sensorPos == std::string::npos) {
180*08777fb0SLewanczyk, Dawid           CROW_LOG_DEBUG << "Adding sensor " << sensorName;
181*08777fb0SLewanczyk, Dawid 
182*08777fb0SLewanczyk, Dawid           sensorNames.emplace(sensorName);
183*08777fb0SLewanczyk, Dawid         }
184*08777fb0SLewanczyk, Dawid       }
185*08777fb0SLewanczyk, Dawid     };
186*08777fb0SLewanczyk, Dawid     CROW_LOG_DEBUG << "Found " << sensorNames.size() << " Sensor names";
187*08777fb0SLewanczyk, Dawid 
188*08777fb0SLewanczyk, Dawid     if (!foundChassis) {
189*08777fb0SLewanczyk, Dawid       CROW_LOG_INFO << "Unable to find chassis named " << asyncResp->chassisId;
190*08777fb0SLewanczyk, Dawid       asyncResp->res.code = static_cast<int>(HttpRespCode::NOT_FOUND);
191*08777fb0SLewanczyk, Dawid     } else {
192*08777fb0SLewanczyk, Dawid       callback(sensorNames);
193*08777fb0SLewanczyk, Dawid     }
194*08777fb0SLewanczyk, Dawid   };
195*08777fb0SLewanczyk, Dawid 
196*08777fb0SLewanczyk, Dawid   // Make call to EntityManager to find all chassis objects
197*08777fb0SLewanczyk, Dawid   crow::connections::system_bus->async_method_call(resp_handler, entityManager);
198*08777fb0SLewanczyk, Dawid }
199*08777fb0SLewanczyk, Dawid 
200*08777fb0SLewanczyk, Dawid /**
201*08777fb0SLewanczyk, Dawid  * @brief Builds a json sensor representation of a sensor.
202*08777fb0SLewanczyk, Dawid  * @param sensorName  The name of the sensor to be built
203*08777fb0SLewanczyk, Dawid  * @param sensorType  The type (temperature, fan_tach, ect) of the sensor to
204*08777fb0SLewanczyk, Dawid  * build
205*08777fb0SLewanczyk, Dawid  * @param interfacesDict  A dictionary of the interfaces and properties of said
206*08777fb0SLewanczyk, Dawid  * interfaces to be built from
207*08777fb0SLewanczyk, Dawid  * @param sensor_json  The json object to fill
208*08777fb0SLewanczyk, Dawid  */
209*08777fb0SLewanczyk, Dawid void objectInterfacesToJson(
210*08777fb0SLewanczyk, Dawid     const std::string& sensorName, const std::string& sensorType,
211*08777fb0SLewanczyk, Dawid     const boost::container::flat_map<
212*08777fb0SLewanczyk, Dawid         std::string,
213*08777fb0SLewanczyk, Dawid         boost::container::flat_map<dbus::string, dbus::dbus_variant>>&
214*08777fb0SLewanczyk, Dawid         interfacesDict,
215*08777fb0SLewanczyk, Dawid     nlohmann::json& sensor_json) {
216*08777fb0SLewanczyk, Dawid   // We need a value interface before we can do anything with it
217*08777fb0SLewanczyk, Dawid   auto value_it = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
218*08777fb0SLewanczyk, Dawid   if (value_it == interfacesDict.end()) {
219*08777fb0SLewanczyk, Dawid     CROW_LOG_ERROR << "Sensor doesn't have a value interface";
220*08777fb0SLewanczyk, Dawid     return;
221*08777fb0SLewanczyk, Dawid   }
222*08777fb0SLewanczyk, Dawid 
223*08777fb0SLewanczyk, Dawid   // Assume values exist as is (10^0 == 1) if no scale exists
224*08777fb0SLewanczyk, Dawid   int64_t scaleMultiplier = 0;
225*08777fb0SLewanczyk, Dawid 
226*08777fb0SLewanczyk, Dawid   auto scale_it = value_it->second.find("Scale");
227*08777fb0SLewanczyk, Dawid   // If a scale exists, pull value as int64, and use the scaling.
228*08777fb0SLewanczyk, Dawid   if (scale_it != value_it->second.end()) {
229*08777fb0SLewanczyk, Dawid     const int64_t* int64Value = boost::get<int64_t>(&scale_it->second);
230*08777fb0SLewanczyk, Dawid     if (int64Value != nullptr) {
231*08777fb0SLewanczyk, Dawid       scaleMultiplier = *int64Value;
232*08777fb0SLewanczyk, Dawid     }
233*08777fb0SLewanczyk, Dawid   }
234*08777fb0SLewanczyk, Dawid 
235*08777fb0SLewanczyk, Dawid   sensor_json["MemberId"] = sensorName;
236*08777fb0SLewanczyk, Dawid   sensor_json["Name"] = sensorName;
237*08777fb0SLewanczyk, Dawid   sensor_json["Status"]["State"] = "Enabled";
238*08777fb0SLewanczyk, Dawid   sensor_json["Status"]["Health"] = "OK";
239*08777fb0SLewanczyk, Dawid 
240*08777fb0SLewanczyk, Dawid   // Parameter to set to override the type we get from dbus, and force it to
241*08777fb0SLewanczyk, Dawid   // int, regardless of what is available.  This is used for schemas like fan,
242*08777fb0SLewanczyk, Dawid   // that require integers, not floats.
243*08777fb0SLewanczyk, Dawid   bool forceToInt = false;
244*08777fb0SLewanczyk, Dawid 
245*08777fb0SLewanczyk, Dawid   const char* unit = "Reading";
246*08777fb0SLewanczyk, Dawid   if (sensorType == "temperature") {
247*08777fb0SLewanczyk, Dawid     unit = "ReadingCelsius";
248*08777fb0SLewanczyk, Dawid     // TODO(ed) Documentation says that path should be type fan_tach,
249*08777fb0SLewanczyk, Dawid     // implementation seems to implement fan
250*08777fb0SLewanczyk, Dawid   } else if (sensorType == "fan" || sensorType == "fan_tach") {
251*08777fb0SLewanczyk, Dawid     unit = "Reading";
252*08777fb0SLewanczyk, Dawid     sensor_json["ReadingUnits"] = "RPM";
253*08777fb0SLewanczyk, Dawid     forceToInt = true;
254*08777fb0SLewanczyk, Dawid   } else if (sensorType == "voltage") {
255*08777fb0SLewanczyk, Dawid     unit = "ReadingVolts";
256*08777fb0SLewanczyk, Dawid   } else {
257*08777fb0SLewanczyk, Dawid     CROW_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
258*08777fb0SLewanczyk, Dawid     return;
259*08777fb0SLewanczyk, Dawid   }
260*08777fb0SLewanczyk, Dawid   // Map of dbus interface name, dbus property name and redfish property_name
261*08777fb0SLewanczyk, Dawid   std::vector<std::tuple<const char*, const char*, const char*>> properties;
262*08777fb0SLewanczyk, Dawid   properties.reserve(7);
263*08777fb0SLewanczyk, Dawid 
264*08777fb0SLewanczyk, Dawid   properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
265*08777fb0SLewanczyk, Dawid   properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
266*08777fb0SLewanczyk, Dawid                           "WarningHigh", "UpperThresholdNonCritical");
267*08777fb0SLewanczyk, Dawid   properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
268*08777fb0SLewanczyk, Dawid                           "WarningLow", "LowerThresholdNonCritical");
269*08777fb0SLewanczyk, Dawid   properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
270*08777fb0SLewanczyk, Dawid                           "CriticalHigh", "UpperThresholdCritical");
271*08777fb0SLewanczyk, Dawid   properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
272*08777fb0SLewanczyk, Dawid                           "CriticalLow", "LowerThresholdCritical");
273*08777fb0SLewanczyk, Dawid 
274*08777fb0SLewanczyk, Dawid   if (sensorType == "temperature") {
275*08777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
276*08777fb0SLewanczyk, Dawid                             "MinReadingRangeTemp");
277*08777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
278*08777fb0SLewanczyk, Dawid                             "MaxReadingRangeTemp");
279*08777fb0SLewanczyk, Dawid   } else {
280*08777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
281*08777fb0SLewanczyk, Dawid                             "MinReadingRange");
282*08777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
283*08777fb0SLewanczyk, Dawid                             "MaxReadingRange");
284*08777fb0SLewanczyk, Dawid   }
285*08777fb0SLewanczyk, Dawid 
286*08777fb0SLewanczyk, Dawid   for (const std::tuple<const char*, const char*, const char*>& p :
287*08777fb0SLewanczyk, Dawid        properties) {
288*08777fb0SLewanczyk, Dawid     auto interfaceProperties = interfacesDict.find(std::get<0>(p));
289*08777fb0SLewanczyk, Dawid     if (interfaceProperties != interfacesDict.end()) {
290*08777fb0SLewanczyk, Dawid       auto value_it = interfaceProperties->second.find(std::get<1>(p));
291*08777fb0SLewanczyk, Dawid       if (value_it != interfaceProperties->second.end()) {
292*08777fb0SLewanczyk, Dawid         const dbus::dbus_variant& valueVariant = value_it->second;
293*08777fb0SLewanczyk, Dawid         nlohmann::json& value_it = sensor_json[std::get<2>(p)];
294*08777fb0SLewanczyk, Dawid         // Attempt to pull the int64 directly
295*08777fb0SLewanczyk, Dawid         const int64_t* int64Value = boost::get<int64_t>(&valueVariant);
296*08777fb0SLewanczyk, Dawid 
297*08777fb0SLewanczyk, Dawid         if (int64Value != nullptr) {
298*08777fb0SLewanczyk, Dawid           if (forceToInt || scaleMultiplier >= 0) {
299*08777fb0SLewanczyk, Dawid             value_it = *int64Value * std::pow(10, scaleMultiplier);
300*08777fb0SLewanczyk, Dawid           } else {
301*08777fb0SLewanczyk, Dawid             value_it = *int64Value *
302*08777fb0SLewanczyk, Dawid                        std::pow(10, static_cast<double>(scaleMultiplier));
303*08777fb0SLewanczyk, Dawid           }
304*08777fb0SLewanczyk, Dawid         }
305*08777fb0SLewanczyk, Dawid         // Attempt to pull the float directly
306*08777fb0SLewanczyk, Dawid         const double* doubleValue = boost::get<double>(&valueVariant);
307*08777fb0SLewanczyk, Dawid 
308*08777fb0SLewanczyk, Dawid         if (doubleValue != nullptr) {
309*08777fb0SLewanczyk, Dawid           if (!forceToInt) {
310*08777fb0SLewanczyk, Dawid             value_it = *doubleValue *
311*08777fb0SLewanczyk, Dawid                        std::pow(10, static_cast<double>(scaleMultiplier));
312*08777fb0SLewanczyk, Dawid           } else {
313*08777fb0SLewanczyk, Dawid             value_it = static_cast<int64_t>(*doubleValue *
314*08777fb0SLewanczyk, Dawid                                             std::pow(10, scaleMultiplier));
315*08777fb0SLewanczyk, Dawid           }
316*08777fb0SLewanczyk, Dawid         }
317*08777fb0SLewanczyk, Dawid       }
318*08777fb0SLewanczyk, Dawid     }
319*08777fb0SLewanczyk, Dawid   }
320*08777fb0SLewanczyk, Dawid }
321*08777fb0SLewanczyk, Dawid 
322*08777fb0SLewanczyk, Dawid /**
323*08777fb0SLewanczyk, Dawid  * @brief Entry point for retrieving sensors data related to requested
324*08777fb0SLewanczyk, Dawid  *        chassis.
325*08777fb0SLewanczyk, Dawid  * @param asyncResp   Pointer to object holding response data
326*08777fb0SLewanczyk, Dawid  */
327*08777fb0SLewanczyk, Dawid void getChassisData(const std::shared_ptr<AsyncResp>& asyncResp) {
328*08777fb0SLewanczyk, Dawid   CROW_LOG_DEBUG << "getChassisData";
329*08777fb0SLewanczyk, Dawid   auto getChassisCb = [&, asyncResp](boost::container::flat_set<std::string>&
330*08777fb0SLewanczyk, Dawid                                          sensorNames) {
331*08777fb0SLewanczyk, Dawid     CROW_LOG_DEBUG << "getChassisCb Done";
332*08777fb0SLewanczyk, Dawid     auto getConnectionCb =
333*08777fb0SLewanczyk, Dawid         [&, asyncResp, sensorNames](
334*08777fb0SLewanczyk, Dawid             const boost::container::flat_set<std::string>& connections) {
335*08777fb0SLewanczyk, Dawid           CROW_LOG_DEBUG << "getConnectionCb Done";
336*08777fb0SLewanczyk, Dawid           // Get managed objects from all services exposing sensors
337*08777fb0SLewanczyk, Dawid           for (const std::string& connection : connections) {
338*08777fb0SLewanczyk, Dawid             // Response handler to process managed objects
339*08777fb0SLewanczyk, Dawid             auto getManagedObjectsCb = [&, asyncResp, sensorNames](
340*08777fb0SLewanczyk, Dawid                                            const boost::system::error_code ec,
341*08777fb0SLewanczyk, Dawid                                            ManagedObjectsVectorType& resp) {
342*08777fb0SLewanczyk, Dawid               // Go through all objects and update response with
343*08777fb0SLewanczyk, Dawid               // sensor data
344*08777fb0SLewanczyk, Dawid               for (const auto& objDictEntry : resp) {
345*08777fb0SLewanczyk, Dawid                 const std::string& objPath = objDictEntry.first.value;
346*08777fb0SLewanczyk, Dawid                 CROW_LOG_DEBUG << "getManagedObjectsCb parsing object "
347*08777fb0SLewanczyk, Dawid                                << objPath;
348*08777fb0SLewanczyk, Dawid                 if (!boost::starts_with(objPath, DBUS_SENSOR_PREFIX)) {
349*08777fb0SLewanczyk, Dawid                   CROW_LOG_ERROR << "Got path that isn't in sensor namespace: "
350*08777fb0SLewanczyk, Dawid                                  << objPath;
351*08777fb0SLewanczyk, Dawid                   continue;
352*08777fb0SLewanczyk, Dawid                 }
353*08777fb0SLewanczyk, Dawid                 std::vector<std::string> split;
354*08777fb0SLewanczyk, Dawid                 // Reserve space for
355*08777fb0SLewanczyk, Dawid                 // /xyz/openbmc_project/Sensors/<name>/<subname>
356*08777fb0SLewanczyk, Dawid                 split.reserve(6);
357*08777fb0SLewanczyk, Dawid                 boost::algorithm::split(split, objPath, boost::is_any_of("/"));
358*08777fb0SLewanczyk, Dawid                 if (split.size() < 6) {
359*08777fb0SLewanczyk, Dawid                   CROW_LOG_ERROR << "Got path that isn't long enough "
360*08777fb0SLewanczyk, Dawid                                  << objPath;
361*08777fb0SLewanczyk, Dawid                   continue;
362*08777fb0SLewanczyk, Dawid                 }
363*08777fb0SLewanczyk, Dawid                 // These indexes aren't intuitive, as boost::split puts an empty
364*08777fb0SLewanczyk, Dawid                 // string at the beggining
365*08777fb0SLewanczyk, Dawid                 const std::string& sensorType = split[4];
366*08777fb0SLewanczyk, Dawid                 const std::string& sensorName = split[5];
367*08777fb0SLewanczyk, Dawid                 CROW_LOG_DEBUG << "sensorName " << sensorName << " sensorType "
368*08777fb0SLewanczyk, Dawid                                << sensorType;
369*08777fb0SLewanczyk, Dawid                 if (sensorNames.find(sensorName) == sensorNames.end()) {
370*08777fb0SLewanczyk, Dawid                   CROW_LOG_ERROR << sensorName << " not in sensor list ";
371*08777fb0SLewanczyk, Dawid                   continue;
372*08777fb0SLewanczyk, Dawid                 }
373*08777fb0SLewanczyk, Dawid 
374*08777fb0SLewanczyk, Dawid                 const char* fieldName = nullptr;
375*08777fb0SLewanczyk, Dawid                 if (sensorType == "temperature") {
376*08777fb0SLewanczyk, Dawid                   fieldName = "Temperatures";
377*08777fb0SLewanczyk, Dawid                 } else if (sensorType == "fan" || sensorType == "fan_tach") {
378*08777fb0SLewanczyk, Dawid                   fieldName = "Fans";
379*08777fb0SLewanczyk, Dawid                 } else if (sensorType == "voltage") {
380*08777fb0SLewanczyk, Dawid                   fieldName = "Voltages";
381*08777fb0SLewanczyk, Dawid                 } else if (sensorType == "current") {
382*08777fb0SLewanczyk, Dawid                   fieldName = "PowerSupply";
383*08777fb0SLewanczyk, Dawid                 } else if (sensorType == "power") {
384*08777fb0SLewanczyk, Dawid                   fieldName = "PowerSupply";
385*08777fb0SLewanczyk, Dawid                 } else {
386*08777fb0SLewanczyk, Dawid                   CROW_LOG_ERROR << "Unsure how to handle sensorType "
387*08777fb0SLewanczyk, Dawid                                  << sensorType;
388*08777fb0SLewanczyk, Dawid                   continue;
389*08777fb0SLewanczyk, Dawid                 }
390*08777fb0SLewanczyk, Dawid 
391*08777fb0SLewanczyk, Dawid                 nlohmann::json& temp_array =
392*08777fb0SLewanczyk, Dawid                     asyncResp->res.json_value[fieldName];
393*08777fb0SLewanczyk, Dawid 
394*08777fb0SLewanczyk, Dawid                 // Create the array if it doesn't yet exist
395*08777fb0SLewanczyk, Dawid                 if (temp_array.is_array() == false) {
396*08777fb0SLewanczyk, Dawid                   temp_array = nlohmann::json::array();
397*08777fb0SLewanczyk, Dawid                 }
398*08777fb0SLewanczyk, Dawid 
399*08777fb0SLewanczyk, Dawid                 temp_array.push_back(nlohmann::json::object());
400*08777fb0SLewanczyk, Dawid                 nlohmann::json& sensor_json = temp_array.back();
401*08777fb0SLewanczyk, Dawid                 sensor_json["@odata.id"] = "/redfish/v1/Chassis/" +
402*08777fb0SLewanczyk, Dawid                                            asyncResp->chassisId + "/Thermal#/" +
403*08777fb0SLewanczyk, Dawid                                            sensorName;
404*08777fb0SLewanczyk, Dawid                 objectInterfacesToJson(sensorName, sensorType,
405*08777fb0SLewanczyk, Dawid                                        objDictEntry.second, sensor_json);
406*08777fb0SLewanczyk, Dawid               }
407*08777fb0SLewanczyk, Dawid             };
408*08777fb0SLewanczyk, Dawid 
409*08777fb0SLewanczyk, Dawid             dbus::endpoint ep(connection, "/xyz/openbmc_project/Sensors",
410*08777fb0SLewanczyk, Dawid                               "org.freedesktop.DBus.ObjectManager",
411*08777fb0SLewanczyk, Dawid                               "GetManagedObjects");
412*08777fb0SLewanczyk, Dawid             crow::connections::system_bus->async_method_call(
413*08777fb0SLewanczyk, Dawid                 getManagedObjectsCb, ep);
414*08777fb0SLewanczyk, Dawid           };
415*08777fb0SLewanczyk, Dawid         };
416*08777fb0SLewanczyk, Dawid     // Get connections and then pass it to get sensors
417*08777fb0SLewanczyk, Dawid     getConnections(asyncResp, sensorNames, std::move(getConnectionCb));
418*08777fb0SLewanczyk, Dawid   };
419*08777fb0SLewanczyk, Dawid 
420*08777fb0SLewanczyk, Dawid   // Get chassis information related to sensors
421*08777fb0SLewanczyk, Dawid   getChassis(asyncResp, std::move(getChassisCb));
422*08777fb0SLewanczyk, Dawid };
423*08777fb0SLewanczyk, Dawid 
424*08777fb0SLewanczyk, Dawid }  // namespace redfish
425