xref: /openbmc/bmcweb/features/redfish/lib/sensors.hpp (revision 2474adfaf23ea9409891924662ec36e7217b4535)
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,
50*2474adfaSEd Tanous                      const std::initializer_list<const char*> types,
51*2474adfaSEd Tanous                      const std::string& subNode) :
52*2474adfaSEd Tanous         chassisId(chassisId),
53*2474adfaSEd 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 
711abe55efSEd Tanous     void setErrorStatus()
721abe55efSEd Tanous     {
73e0d918bcSEd Tanous         res.result(boost::beast::http::status::internal_server_error);
7408777fb0SLewanczyk, Dawid     }
7508777fb0SLewanczyk, Dawid 
7655c7b7a2SEd Tanous     crow::Response& res;
77588c3f0dSKowalski, Kamil     std::string chassisId{};
7808777fb0SLewanczyk, Dawid     const std::vector<const char*> types;
79*2474adfaSEd Tanous     std::string chassisSubNode{};
8008777fb0SLewanczyk, Dawid };
8108777fb0SLewanczyk, Dawid 
8208777fb0SLewanczyk, Dawid /**
8308777fb0SLewanczyk, Dawid  * @brief Creates connections necessary for chassis sensors
84588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp Pointer to object holding response data
8508777fb0SLewanczyk, Dawid  * @param sensorNames Sensors retrieved from chassis
8608777fb0SLewanczyk, Dawid  * @param callback Callback for processing gathered connections
8708777fb0SLewanczyk, Dawid  */
8808777fb0SLewanczyk, Dawid template <typename Callback>
89588c3f0dSKowalski, Kamil void getConnections(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
9008777fb0SLewanczyk, Dawid                     const boost::container::flat_set<std::string>& sensorNames,
911abe55efSEd Tanous                     Callback&& callback)
921abe55efSEd Tanous {
9355c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getConnections enter";
9403b5bae3SJames Feist     const std::string path = "/xyz/openbmc_project/sensors";
9508777fb0SLewanczyk, Dawid     const std::array<std::string, 1> interfaces = {
9608777fb0SLewanczyk, Dawid         "xyz.openbmc_project.Sensor.Value"};
9708777fb0SLewanczyk, Dawid 
9808777fb0SLewanczyk, Dawid     // Response handler for parsing objects subtree
991abe55efSEd Tanous     auto respHandler = [callback{std::move(callback)}, SensorsAsyncResp,
1001abe55efSEd Tanous                         sensorNames](const boost::system::error_code ec,
1011abe55efSEd Tanous                                      const GetSubTreeType& subtree) {
10255c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getConnections resp_handler enter";
1031abe55efSEd Tanous         if (ec)
1041abe55efSEd Tanous         {
105588c3f0dSKowalski, Kamil             SensorsAsyncResp->setErrorStatus();
1061abe55efSEd Tanous             BMCWEB_LOG_ERROR << "getConnections resp_handler: Dbus error "
1071abe55efSEd Tanous                              << ec;
10808777fb0SLewanczyk, Dawid             return;
10908777fb0SLewanczyk, Dawid         }
11008777fb0SLewanczyk, Dawid 
11155c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
11208777fb0SLewanczyk, Dawid 
11308777fb0SLewanczyk, Dawid         // Make unique list of connections only for requested sensor types and
11408777fb0SLewanczyk, Dawid         // found in the chassis
11508777fb0SLewanczyk, Dawid         boost::container::flat_set<std::string> connections;
1161abe55efSEd Tanous         // Intrinsic to avoid malloc.  Most systems will have < 8 sensor
1171abe55efSEd Tanous         // producers
11808777fb0SLewanczyk, Dawid         connections.reserve(8);
11908777fb0SLewanczyk, Dawid 
12055c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames.size();
1211abe55efSEd Tanous         for (const std::string& tsensor : sensorNames)
1221abe55efSEd Tanous         {
12355c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor;
12408777fb0SLewanczyk, Dawid         }
12508777fb0SLewanczyk, Dawid 
12608777fb0SLewanczyk, Dawid         for (const std::pair<
12708777fb0SLewanczyk, Dawid                  std::string,
12808777fb0SLewanczyk, Dawid                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
1291abe55efSEd Tanous                  object : subtree)
1301abe55efSEd Tanous         {
1311abe55efSEd Tanous             for (const char* type : SensorsAsyncResp->types)
1321abe55efSEd Tanous             {
1331abe55efSEd Tanous                 if (boost::starts_with(object.first, type))
1341abe55efSEd Tanous                 {
13508777fb0SLewanczyk, Dawid                     auto lastPos = object.first.rfind('/');
1361abe55efSEd Tanous                     if (lastPos != std::string::npos)
1371abe55efSEd Tanous                     {
1381abe55efSEd Tanous                         std::string sensorName =
1391abe55efSEd Tanous                             object.first.substr(lastPos + 1);
14008777fb0SLewanczyk, Dawid 
1411abe55efSEd Tanous                         if (sensorNames.find(sensorName) != sensorNames.end())
1421abe55efSEd Tanous                         {
14355c7b7a2SEd Tanous                             // For each Connection name
1441abe55efSEd Tanous                             for (const std::pair<std::string,
1451abe55efSEd Tanous                                                  std::vector<std::string>>&
1461abe55efSEd Tanous                                      objData : object.second)
1471abe55efSEd Tanous                             {
1481abe55efSEd Tanous                                 BMCWEB_LOG_DEBUG << "Adding connection: "
1491abe55efSEd Tanous                                                  << objData.first;
15008777fb0SLewanczyk, Dawid                                 connections.insert(objData.first);
15108777fb0SLewanczyk, Dawid                             }
15208777fb0SLewanczyk, Dawid                         }
15308777fb0SLewanczyk, Dawid                     }
15408777fb0SLewanczyk, Dawid                     break;
15508777fb0SLewanczyk, Dawid                 }
15608777fb0SLewanczyk, Dawid             }
15708777fb0SLewanczyk, Dawid         }
15855c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections";
15908777fb0SLewanczyk, Dawid         callback(std::move(connections));
16055c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getConnections resp_handler exit";
16108777fb0SLewanczyk, Dawid     };
16208777fb0SLewanczyk, Dawid 
16308777fb0SLewanczyk, Dawid     // Make call to ObjectMapper to find all sensors objects
16455c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
16555c7b7a2SEd Tanous         std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
1661abe55efSEd Tanous         "/xyz/openbmc_project/object_mapper",
1671abe55efSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 2, interfaces);
16855c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getConnections exit";
16908777fb0SLewanczyk, Dawid }
17008777fb0SLewanczyk, Dawid 
17108777fb0SLewanczyk, Dawid /**
17208777fb0SLewanczyk, Dawid  * @brief Retrieves requested chassis sensors and redundancy data from DBus .
173588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
17408777fb0SLewanczyk, Dawid  * @param callback  Callback for next step in gathered sensor processing
17508777fb0SLewanczyk, Dawid  */
17608777fb0SLewanczyk, Dawid template <typename Callback>
177588c3f0dSKowalski, Kamil void getChassis(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
1781abe55efSEd Tanous                 Callback&& callback)
1791abe55efSEd Tanous {
18055c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis enter";
18108777fb0SLewanczyk, Dawid     // Process response from EntityManager and extract chassis data
1821abe55efSEd Tanous     auto respHandler = [callback{std::move(callback)},
1831abe55efSEd Tanous                         SensorsAsyncResp](const boost::system::error_code ec,
1841abe55efSEd Tanous                                           ManagedObjectsVectorType& resp) {
18555c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassis respHandler enter";
1861abe55efSEd Tanous         if (ec)
1871abe55efSEd Tanous         {
18855c7b7a2SEd Tanous             BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec;
189588c3f0dSKowalski, Kamil             SensorsAsyncResp->setErrorStatus();
19008777fb0SLewanczyk, Dawid             return;
19108777fb0SLewanczyk, Dawid         }
19208777fb0SLewanczyk, Dawid         boost::container::flat_set<std::string> sensorNames;
19308777fb0SLewanczyk, Dawid 
194588c3f0dSKowalski, Kamil         //   SensorsAsyncResp->chassisId
195daf36e2eSEd Tanous         bool foundChassis = false;
196daf36e2eSEd Tanous         std::vector<std::string> split;
197daf36e2eSEd Tanous         // Reserve space for
198daf36e2eSEd Tanous         // /xyz/openbmc_project/inventory/<name>/<subname> + 3 subnames
199daf36e2eSEd Tanous         split.reserve(8);
200daf36e2eSEd Tanous 
2011abe55efSEd Tanous         for (const auto& objDictEntry : resp)
2021abe55efSEd Tanous         {
203daf36e2eSEd Tanous             const std::string& objectPath =
204daf36e2eSEd Tanous                 static_cast<const std::string&>(objDictEntry.first);
205daf36e2eSEd Tanous             boost::algorithm::split(split, objectPath, boost::is_any_of("/"));
2061abe55efSEd Tanous             if (split.size() < 2)
2071abe55efSEd Tanous             {
2081abe55efSEd Tanous                 BMCWEB_LOG_ERROR << "Got path that isn't long enough "
2091abe55efSEd Tanous                                  << objectPath;
210daf36e2eSEd Tanous                 split.clear();
211daf36e2eSEd Tanous                 continue;
212daf36e2eSEd Tanous             }
213daf36e2eSEd Tanous             const std::string& sensorName = split.end()[-1];
214daf36e2eSEd Tanous             const std::string& chassisName = split.end()[-2];
215daf36e2eSEd Tanous 
2161abe55efSEd Tanous             if (chassisName != SensorsAsyncResp->chassisId)
2171abe55efSEd Tanous             {
218daf36e2eSEd Tanous                 split.clear();
219daf36e2eSEd Tanous                 continue;
220daf36e2eSEd Tanous             }
22155c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "New sensor: " << sensorName;
222daf36e2eSEd Tanous             foundChassis = true;
22308777fb0SLewanczyk, Dawid             sensorNames.emplace(sensorName);
224daf36e2eSEd Tanous             split.clear();
22508777fb0SLewanczyk, Dawid         };
22655c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "Found " << sensorNames.size() << " Sensor names";
22708777fb0SLewanczyk, Dawid 
2281abe55efSEd Tanous         if (!foundChassis)
2291abe55efSEd Tanous         {
23055c7b7a2SEd Tanous             BMCWEB_LOG_INFO << "Unable to find chassis named "
231588c3f0dSKowalski, Kamil                             << SensorsAsyncResp->chassisId;
232f12894f8SJason M. Bills             messages::resourceNotFound(SensorsAsyncResp->res, "Chassis",
233f12894f8SJason M. Bills                                        SensorsAsyncResp->chassisId);
2341abe55efSEd Tanous         }
2351abe55efSEd Tanous         else
2361abe55efSEd Tanous         {
23708777fb0SLewanczyk, Dawid             callback(sensorNames);
23808777fb0SLewanczyk, Dawid         }
23955c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassis respHandler exit";
24008777fb0SLewanczyk, Dawid     };
24108777fb0SLewanczyk, Dawid 
24208777fb0SLewanczyk, Dawid     // Make call to EntityManager to find all chassis objects
24355c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
24455c7b7a2SEd Tanous         respHandler, "xyz.openbmc_project.EntityManager", "/",
2457885954aSLewanczyk, Dawid         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
24655c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassis exit";
24708777fb0SLewanczyk, Dawid }
24808777fb0SLewanczyk, Dawid 
24908777fb0SLewanczyk, Dawid /**
25008777fb0SLewanczyk, Dawid  * @brief Builds a json sensor representation of a sensor.
25108777fb0SLewanczyk, Dawid  * @param sensorName  The name of the sensor to be built
252274fad5aSGunnar Mills  * @param sensorType  The type (temperature, fan_tach, etc) of the sensor to
25308777fb0SLewanczyk, Dawid  * build
25408777fb0SLewanczyk, Dawid  * @param interfacesDict  A dictionary of the interfaces and properties of said
25508777fb0SLewanczyk, Dawid  * interfaces to be built from
25608777fb0SLewanczyk, Dawid  * @param sensor_json  The json object to fill
25708777fb0SLewanczyk, Dawid  */
25808777fb0SLewanczyk, Dawid void objectInterfacesToJson(
25908777fb0SLewanczyk, Dawid     const std::string& sensorName, const std::string& sensorType,
26008777fb0SLewanczyk, Dawid     const boost::container::flat_map<
261aa2e59c1SEd Tanous         std::string, boost::container::flat_map<std::string, SensorVariant>>&
26208777fb0SLewanczyk, Dawid         interfacesDict,
2631abe55efSEd Tanous     nlohmann::json& sensor_json)
2641abe55efSEd Tanous {
26508777fb0SLewanczyk, Dawid     // We need a value interface before we can do anything with it
26655c7b7a2SEd Tanous     auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
2671abe55efSEd Tanous     if (valueIt == interfacesDict.end())
2681abe55efSEd Tanous     {
26955c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface";
27008777fb0SLewanczyk, Dawid         return;
27108777fb0SLewanczyk, Dawid     }
27208777fb0SLewanczyk, Dawid 
27308777fb0SLewanczyk, Dawid     // Assume values exist as is (10^0 == 1) if no scale exists
27408777fb0SLewanczyk, Dawid     int64_t scaleMultiplier = 0;
27508777fb0SLewanczyk, Dawid 
27655c7b7a2SEd Tanous     auto scaleIt = valueIt->second.find("Scale");
27708777fb0SLewanczyk, Dawid     // If a scale exists, pull value as int64, and use the scaling.
2781abe55efSEd Tanous     if (scaleIt != valueIt->second.end())
2791abe55efSEd Tanous     {
2801abe55efSEd Tanous         const int64_t* int64Value =
2811abe55efSEd Tanous             mapbox::getPtr<const int64_t>(scaleIt->second);
2821abe55efSEd Tanous         if (int64Value != nullptr)
2831abe55efSEd Tanous         {
28408777fb0SLewanczyk, Dawid             scaleMultiplier = *int64Value;
28508777fb0SLewanczyk, Dawid         }
28608777fb0SLewanczyk, Dawid     }
28708777fb0SLewanczyk, Dawid 
28808777fb0SLewanczyk, Dawid     sensor_json["MemberId"] = sensorName;
28908777fb0SLewanczyk, Dawid     sensor_json["Name"] = sensorName;
29008777fb0SLewanczyk, Dawid     sensor_json["Status"]["State"] = "Enabled";
29108777fb0SLewanczyk, Dawid     sensor_json["Status"]["Health"] = "OK";
29208777fb0SLewanczyk, Dawid 
29308777fb0SLewanczyk, Dawid     // Parameter to set to override the type we get from dbus, and force it to
29408777fb0SLewanczyk, Dawid     // int, regardless of what is available.  This is used for schemas like fan,
29508777fb0SLewanczyk, Dawid     // that require integers, not floats.
29608777fb0SLewanczyk, Dawid     bool forceToInt = false;
29708777fb0SLewanczyk, Dawid 
29808777fb0SLewanczyk, Dawid     const char* unit = "Reading";
2991abe55efSEd Tanous     if (sensorType == "temperature")
3001abe55efSEd Tanous     {
30108777fb0SLewanczyk, Dawid         unit = "ReadingCelsius";
3027885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature";
30308777fb0SLewanczyk, Dawid         // TODO(ed) Documentation says that path should be type fan_tach,
30408777fb0SLewanczyk, Dawid         // implementation seems to implement fan
3051abe55efSEd Tanous     }
3061abe55efSEd Tanous     else if (sensorType == "fan" || sensorType == "fan_tach")
3071abe55efSEd Tanous     {
30808777fb0SLewanczyk, Dawid         unit = "Reading";
30908777fb0SLewanczyk, Dawid         sensor_json["ReadingUnits"] = "RPM";
3107885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
31108777fb0SLewanczyk, Dawid         forceToInt = true;
3121abe55efSEd Tanous     }
3136f6d0d32SEd Tanous     else if (sensorType == "fan_pwm")
3146f6d0d32SEd Tanous     {
3156f6d0d32SEd Tanous         unit = "Reading";
3166f6d0d32SEd Tanous         sensor_json["ReadingUnits"] = "Percent";
3176f6d0d32SEd Tanous         sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
3186f6d0d32SEd Tanous         forceToInt = true;
3196f6d0d32SEd Tanous     }
3201abe55efSEd Tanous     else if (sensorType == "voltage")
3211abe55efSEd Tanous     {
32208777fb0SLewanczyk, Dawid         unit = "ReadingVolts";
3237885954aSLewanczyk, Dawid         sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage";
3241abe55efSEd Tanous     }
325*2474adfaSEd Tanous     else if (sensorType == "power")
326*2474adfaSEd Tanous     {
327*2474adfaSEd Tanous         unit = "LastPowerOutputWatts";
328*2474adfaSEd Tanous     }
3291abe55efSEd Tanous     else
3301abe55efSEd Tanous     {
33155c7b7a2SEd Tanous         BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
33208777fb0SLewanczyk, Dawid         return;
33308777fb0SLewanczyk, Dawid     }
33408777fb0SLewanczyk, Dawid     // Map of dbus interface name, dbus property name and redfish property_name
33508777fb0SLewanczyk, Dawid     std::vector<std::tuple<const char*, const char*, const char*>> properties;
33608777fb0SLewanczyk, Dawid     properties.reserve(7);
33708777fb0SLewanczyk, Dawid 
33808777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
33908777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
34008777fb0SLewanczyk, Dawid                             "WarningHigh", "UpperThresholdNonCritical");
34108777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
34208777fb0SLewanczyk, Dawid                             "WarningLow", "LowerThresholdNonCritical");
34308777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
34408777fb0SLewanczyk, Dawid                             "CriticalHigh", "UpperThresholdCritical");
34508777fb0SLewanczyk, Dawid     properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
34608777fb0SLewanczyk, Dawid                             "CriticalLow", "LowerThresholdCritical");
34708777fb0SLewanczyk, Dawid 
348*2474adfaSEd Tanous     // TODO Need to get UpperThresholdFatal and LowerThresholdFatal
349*2474adfaSEd Tanous 
3501abe55efSEd Tanous     if (sensorType == "temperature")
3511abe55efSEd Tanous     {
35208777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
35308777fb0SLewanczyk, Dawid                                 "MinReadingRangeTemp");
35408777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
35508777fb0SLewanczyk, Dawid                                 "MaxReadingRangeTemp");
3561abe55efSEd Tanous     }
3571abe55efSEd Tanous     else
3581abe55efSEd Tanous     {
35908777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
36008777fb0SLewanczyk, Dawid                                 "MinReadingRange");
36108777fb0SLewanczyk, Dawid         properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
36208777fb0SLewanczyk, Dawid                                 "MaxReadingRange");
36308777fb0SLewanczyk, Dawid     }
36408777fb0SLewanczyk, Dawid 
36508777fb0SLewanczyk, Dawid     for (const std::tuple<const char*, const char*, const char*>& p :
3661abe55efSEd Tanous          properties)
3671abe55efSEd Tanous     {
36808777fb0SLewanczyk, Dawid         auto interfaceProperties = interfacesDict.find(std::get<0>(p));
3691abe55efSEd Tanous         if (interfaceProperties != interfacesDict.end())
3701abe55efSEd Tanous         {
37155c7b7a2SEd Tanous             auto valueIt = interfaceProperties->second.find(std::get<1>(p));
3721abe55efSEd Tanous             if (valueIt != interfaceProperties->second.end())
3731abe55efSEd Tanous             {
37455c7b7a2SEd Tanous                 const SensorVariant& valueVariant = valueIt->second;
37555c7b7a2SEd Tanous                 nlohmann::json& valueIt = sensor_json[std::get<2>(p)];
37608777fb0SLewanczyk, Dawid                 // Attempt to pull the int64 directly
3771abe55efSEd Tanous                 const int64_t* int64Value =
3781abe55efSEd Tanous                     mapbox::getPtr<const int64_t>(valueVariant);
37908777fb0SLewanczyk, Dawid 
3801abe55efSEd Tanous                 const double* doubleValue =
3811abe55efSEd Tanous                     mapbox::getPtr<const double>(valueVariant);
3826f6d0d32SEd Tanous                 double temp = 0.0;
3836f6d0d32SEd Tanous                 if (int64Value != nullptr)
3841abe55efSEd Tanous                 {
3856f6d0d32SEd Tanous                     temp = *int64Value;
3866f6d0d32SEd Tanous                 }
3876f6d0d32SEd Tanous                 else if (doubleValue != nullptr)
3881abe55efSEd Tanous                 {
3896f6d0d32SEd Tanous                     temp = *doubleValue;
3901abe55efSEd Tanous                 }
3911abe55efSEd Tanous                 else
3921abe55efSEd Tanous                 {
3936f6d0d32SEd Tanous                     BMCWEB_LOG_ERROR
3946f6d0d32SEd Tanous                         << "Got value interface that wasn't int or double";
3956f6d0d32SEd Tanous                     continue;
39608777fb0SLewanczyk, Dawid                 }
3976f6d0d32SEd Tanous                 temp = temp * std::pow(10, scaleMultiplier);
3986f6d0d32SEd Tanous                 if (forceToInt)
3996f6d0d32SEd Tanous                 {
4006f6d0d32SEd Tanous                     valueIt = static_cast<int64_t>(temp);
4016f6d0d32SEd Tanous                 }
4026f6d0d32SEd Tanous                 else
4036f6d0d32SEd Tanous                 {
4046f6d0d32SEd Tanous                     valueIt = temp;
40508777fb0SLewanczyk, Dawid                 }
40608777fb0SLewanczyk, Dawid             }
40708777fb0SLewanczyk, Dawid         }
40808777fb0SLewanczyk, Dawid     }
40955c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
41008777fb0SLewanczyk, Dawid }
41108777fb0SLewanczyk, Dawid 
41208777fb0SLewanczyk, Dawid /**
41308777fb0SLewanczyk, Dawid  * @brief Entry point for retrieving sensors data related to requested
41408777fb0SLewanczyk, Dawid  *        chassis.
415588c3f0dSKowalski, Kamil  * @param SensorsAsyncResp   Pointer to object holding response data
41608777fb0SLewanczyk, Dawid  */
4171abe55efSEd Tanous void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
4181abe55efSEd Tanous {
41955c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisData enter";
420588c3f0dSKowalski, Kamil     auto getChassisCb = [&, SensorsAsyncResp](
421588c3f0dSKowalski, Kamil                             boost::container::flat_set<std::string>&
42208777fb0SLewanczyk, Dawid                                 sensorNames) {
42355c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassisCb enter";
424588c3f0dSKowalski, Kamil         auto getConnectionCb =
425588c3f0dSKowalski, Kamil             [&, SensorsAsyncResp, sensorNames](
426588c3f0dSKowalski, Kamil                 const boost::container::flat_set<std::string>& connections) {
42755c7b7a2SEd Tanous                 BMCWEB_LOG_DEBUG << "getConnectionCb enter";
42808777fb0SLewanczyk, Dawid                 // Get managed objects from all services exposing sensors
4291abe55efSEd Tanous                 for (const std::string& connection : connections)
4301abe55efSEd Tanous                 {
43108777fb0SLewanczyk, Dawid                     // Response handler to process managed objects
4321abe55efSEd Tanous                     auto getManagedObjectsCb =
4331abe55efSEd Tanous                         [&, SensorsAsyncResp,
4341abe55efSEd Tanous                          sensorNames](const boost::system::error_code ec,
43508777fb0SLewanczyk, Dawid                                       ManagedObjectsVectorType& resp) {
43655c7b7a2SEd Tanous                             BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
4371abe55efSEd Tanous                             if (ec)
4381abe55efSEd Tanous                             {
4391abe55efSEd Tanous                                 BMCWEB_LOG_ERROR
4401abe55efSEd Tanous                                     << "getManagedObjectsCb DBUS error: " << ec;
4417885954aSLewanczyk, Dawid                                 SensorsAsyncResp->setErrorStatus();
4427885954aSLewanczyk, Dawid                                 return;
4437885954aSLewanczyk, Dawid                             }
44408777fb0SLewanczyk, Dawid                             // Go through all objects and update response with
44508777fb0SLewanczyk, Dawid                             // sensor data
4461abe55efSEd Tanous                             for (const auto& objDictEntry : resp)
4471abe55efSEd Tanous                             {
448aa2e59c1SEd Tanous                                 const std::string& objPath =
4491abe55efSEd Tanous                                     static_cast<const std::string&>(
4501abe55efSEd Tanous                                         objDictEntry.first);
4511abe55efSEd Tanous                                 BMCWEB_LOG_DEBUG
4521abe55efSEd Tanous                                     << "getManagedObjectsCb parsing object "
453588c3f0dSKowalski, Kamil                                     << objPath;
454e0d918bcSEd Tanous 
45508777fb0SLewanczyk, Dawid                                 std::vector<std::string> split;
45608777fb0SLewanczyk, Dawid                                 // Reserve space for
45703b5bae3SJames Feist                                 // /xyz/openbmc_project/sensors/<name>/<subname>
45808777fb0SLewanczyk, Dawid                                 split.reserve(6);
4591abe55efSEd Tanous                                 boost::algorithm::split(split, objPath,
4601abe55efSEd Tanous                                                         boost::is_any_of("/"));
4611abe55efSEd Tanous                                 if (split.size() < 6)
4621abe55efSEd Tanous                                 {
4631abe55efSEd Tanous                                     BMCWEB_LOG_ERROR
4641abe55efSEd Tanous                                         << "Got path that isn't long enough "
465588c3f0dSKowalski, Kamil                                         << objPath;
46608777fb0SLewanczyk, Dawid                                     continue;
46708777fb0SLewanczyk, Dawid                                 }
4681abe55efSEd Tanous                                 // These indexes aren't intuitive, as
4691abe55efSEd Tanous                                 // boost::split puts an empty string at the
4701abe55efSEd Tanous                                 // beggining
47108777fb0SLewanczyk, Dawid                                 const std::string& sensorType = split[4];
47208777fb0SLewanczyk, Dawid                                 const std::string& sensorName = split[5];
47355c7b7a2SEd Tanous                                 BMCWEB_LOG_DEBUG << "sensorName " << sensorName
4741abe55efSEd Tanous                                                  << " sensorType "
4751abe55efSEd Tanous                                                  << sensorType;
4761abe55efSEd Tanous                                 if (sensorNames.find(sensorName) ==
4771abe55efSEd Tanous                                     sensorNames.end())
4781abe55efSEd Tanous                                 {
4791abe55efSEd Tanous                                     BMCWEB_LOG_ERROR << sensorName
4801abe55efSEd Tanous                                                      << " not in sensor list ";
48108777fb0SLewanczyk, Dawid                                     continue;
48208777fb0SLewanczyk, Dawid                                 }
48308777fb0SLewanczyk, Dawid 
48408777fb0SLewanczyk, Dawid                                 const char* fieldName = nullptr;
4851abe55efSEd Tanous                                 if (sensorType == "temperature")
4861abe55efSEd Tanous                                 {
48708777fb0SLewanczyk, Dawid                                     fieldName = "Temperatures";
4881abe55efSEd Tanous                                 }
4891abe55efSEd Tanous                                 else if (sensorType == "fan" ||
4906f6d0d32SEd Tanous                                          sensorType == "fan_tach" ||
4916f6d0d32SEd Tanous                                          sensorType == "fan_pwm")
4921abe55efSEd Tanous                                 {
49308777fb0SLewanczyk, Dawid                                     fieldName = "Fans";
4941abe55efSEd Tanous                                 }
4951abe55efSEd Tanous                                 else if (sensorType == "voltage")
4961abe55efSEd Tanous                                 {
49708777fb0SLewanczyk, Dawid                                     fieldName = "Voltages";
4981abe55efSEd Tanous                                 }
4991abe55efSEd Tanous                                 else if (sensorType == "current")
5001abe55efSEd Tanous                                 {
50108777fb0SLewanczyk, Dawid                                     fieldName = "PowerSupply";
5021abe55efSEd Tanous                                 }
5031abe55efSEd Tanous                                 else if (sensorType == "power")
5041abe55efSEd Tanous                                 {
50508777fb0SLewanczyk, Dawid                                     fieldName = "PowerSupply";
5061abe55efSEd Tanous                                 }
5071abe55efSEd Tanous                                 else
5081abe55efSEd Tanous                                 {
5091abe55efSEd Tanous                                     BMCWEB_LOG_ERROR
5101abe55efSEd Tanous                                         << "Unsure how to handle sensorType "
51108777fb0SLewanczyk, Dawid                                         << sensorType;
51208777fb0SLewanczyk, Dawid                                     continue;
51308777fb0SLewanczyk, Dawid                                 }
51408777fb0SLewanczyk, Dawid 
51555c7b7a2SEd Tanous                                 nlohmann::json& tempArray =
51655c7b7a2SEd Tanous                                     SensorsAsyncResp->res.jsonValue[fieldName];
51708777fb0SLewanczyk, Dawid 
51855c7b7a2SEd Tanous                                 tempArray.push_back(
5191abe55efSEd Tanous                                     {{"@odata.id",
5201abe55efSEd Tanous                                       "/redfish/v1/Chassis/" +
521*2474adfaSEd Tanous                                           SensorsAsyncResp->chassisId + "/" +
522*2474adfaSEd Tanous                                           SensorsAsyncResp->chassisSubNode +
523*2474adfaSEd Tanous                                           "#/" + fieldName + "/" +
5246f6d0d32SEd Tanous                                           std::to_string(tempArray.size())}});
52555c7b7a2SEd Tanous                                 nlohmann::json& sensorJson = tempArray.back();
5266f6d0d32SEd Tanous 
527588c3f0dSKowalski, Kamil                                 objectInterfacesToJson(sensorName, sensorType,
5281abe55efSEd Tanous                                                        objDictEntry.second,
5291abe55efSEd Tanous                                                        sensorJson);
53008777fb0SLewanczyk, Dawid                             }
53155c7b7a2SEd Tanous                             BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
53208777fb0SLewanczyk, Dawid                         };
53355c7b7a2SEd Tanous                     crow::connections::systemBus->async_method_call(
5347885954aSLewanczyk, Dawid                         getManagedObjectsCb, connection, "/",
5351abe55efSEd Tanous                         "org.freedesktop.DBus.ObjectManager",
5361abe55efSEd Tanous                         "GetManagedObjects");
53708777fb0SLewanczyk, Dawid                 };
53855c7b7a2SEd Tanous                 BMCWEB_LOG_DEBUG << "getConnectionCb exit";
53908777fb0SLewanczyk, Dawid             };
54055c7b7a2SEd Tanous         // get connections and then pass it to get sensors
5411abe55efSEd Tanous         getConnections(SensorsAsyncResp, sensorNames,
5421abe55efSEd Tanous                        std::move(getConnectionCb));
54355c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "getChassisCb exit";
54408777fb0SLewanczyk, Dawid     };
54508777fb0SLewanczyk, Dawid 
54655c7b7a2SEd Tanous     // get chassis information related to sensors
547588c3f0dSKowalski, Kamil     getChassis(SensorsAsyncResp, std::move(getChassisCb));
54855c7b7a2SEd Tanous     BMCWEB_LOG_DEBUG << "getChassisData exit";
54908777fb0SLewanczyk, Dawid };
55008777fb0SLewanczyk, Dawid 
55108777fb0SLewanczyk, Dawid } // namespace redfish
552