blob: 9aa1da4cc8dd5e3f0f7b3540cac7fa90a0910761 [file] [log] [blame]
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
18#include <math.h>
19#include <dbus_singleton.hpp>
20#include <boost/algorithm/string/predicate.hpp>
21#include <boost/algorithm/string/split.hpp>
22#include <boost/container/flat_map.hpp>
23#include <boost/range/algorithm/replace_copy_if.hpp>
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010024
25namespace redfish {
26
James Feist03b5bae2018-07-06 12:08:09 -070027constexpr const char* DBUS_SENSOR_PREFIX = "/xyz/openbmc_project/sensors/";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010028
29using GetSubTreeType = std::vector<
30 std::pair<std::string,
31 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
32
Ed Tanousaa2e59c2018-04-12 12:17:20 -070033using SensorVariant = sdbusplus::message::variant<int64_t, double>;
34
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010035using ManagedObjectsVectorType = std::vector<std::pair<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070036 sdbusplus::message::object_path,
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010037 boost::container::flat_map<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070038 std::string, boost::container::flat_map<std::string, SensorVariant>>>>;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010039
40/**
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020041 * SensorsAsyncResp
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010042 * Gathers data needed for response processing after async calls are done
43 */
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020044class SensorsAsyncResp {
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010045 public:
Ed Tanous55c7b7a2018-05-22 15:27:24 -070046 SensorsAsyncResp(crow::Response& response, const std::string& chassisId,
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020047 const std::initializer_list<const char*> types)
48 : res(response), chassisId(chassisId), types(types) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -070049 res.jsonValue["@odata.id"] =
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010050 "/redfish/v1/Chassis/" + chassisId + "/Thermal";
51 }
52
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020053 ~SensorsAsyncResp() {
Ed Tanouse0d918b2018-03-27 17:41:04 -070054 if (res.result() == boost::beast::http::status::internal_server_error) {
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010055 // Reset the json object to clear out any data that made it in before the
56 // error happened
57 // todo(ed) handle error condition with proper code
Ed Tanous55c7b7a2018-05-22 15:27:24 -070058 res.jsonValue = nlohmann::json::object();
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010059 }
60 res.end();
61 }
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020062
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010063 void setErrorStatus() {
Ed Tanouse0d918b2018-03-27 17:41:04 -070064 res.result(boost::beast::http::status::internal_server_error);
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010065 }
66
Ed Tanous55c7b7a2018-05-22 15:27:24 -070067 crow::Response& res;
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020068 std::string chassisId{};
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010069 const std::vector<const char*> types;
70};
71
72/**
73 * @brief Creates connections necessary for chassis sensors
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020074 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010075 * @param sensorNames Sensors retrieved from chassis
76 * @param callback Callback for processing gathered connections
77 */
78template <typename Callback>
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020079void getConnections(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010080 const boost::container::flat_set<std::string>& sensorNames,
81 Callback&& callback) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -070082 BMCWEB_LOG_DEBUG << "getConnections enter";
James Feist03b5bae2018-07-06 12:08:09 -070083 const std::string path = "/xyz/openbmc_project/sensors";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010084 const std::array<std::string, 1> interfaces = {
85 "xyz.openbmc_project.Sensor.Value"};
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010086
87 // Response handler for parsing objects subtree
Ed Tanous55c7b7a2018-05-22 15:27:24 -070088 auto respHandler =
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020089 [ callback{std::move(callback)}, SensorsAsyncResp, sensorNames ](
90 const boost::system::error_code ec, const GetSubTreeType& subtree) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -070091 BMCWEB_LOG_DEBUG << "getConnections resp_handler enter";
Ed Tanouse0d918b2018-03-27 17:41:04 -070092 if (ec) {
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020093 SensorsAsyncResp->setErrorStatus();
Ed Tanous55c7b7a2018-05-22 15:27:24 -070094 BMCWEB_LOG_ERROR << "getConnections resp_handler: Dbus error " << ec;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010095 return;
96 }
97
Ed Tanous55c7b7a2018-05-22 15:27:24 -070098 BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010099
100 // Make unique list of connections only for requested sensor types and
101 // found in the chassis
102 boost::container::flat_set<std::string> connections;
103 // Intrinsic to avoid malloc. Most systems will have < 8 sensor producers
104 connections.reserve(8);
105
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700106 BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames.size();
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100107 for (const std::string& tsensor : sensorNames) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700108 BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100109 }
110
111 for (const std::pair<
112 std::string,
113 std::vector<std::pair<std::string, std::vector<std::string>>>>&
114 object : subtree) {
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200115 for (const char* type : SensorsAsyncResp->types) {
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100116 if (boost::starts_with(object.first, type)) {
117 auto lastPos = object.first.rfind('/');
118 if (lastPos != std::string::npos) {
119 std::string sensorName = object.first.substr(lastPos + 1);
120
121 if (sensorNames.find(sensorName) != sensorNames.end()) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700122 // For each Connection name
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100123 for (const std::pair<std::string, std::vector<std::string>>&
124 objData : object.second) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700125 BMCWEB_LOG_DEBUG << "Adding connection: " << objData.first;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100126 connections.insert(objData.first);
127 }
128 }
129 }
130 break;
131 }
132 }
133 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700134 BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100135 callback(std::move(connections));
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700136 BMCWEB_LOG_DEBUG << "getConnections resp_handler exit";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100137 };
138
139 // Make call to ObjectMapper to find all sensors objects
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700140 crow::connections::systemBus->async_method_call(
141 std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700142 "/xyz/openbmc_project/object_mapper", "xyz.openbmc_project.ObjectMapper",
143 "GetSubTree", path, 2, interfaces);
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700144 BMCWEB_LOG_DEBUG << "getConnections exit";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100145}
146
147/**
148 * @brief Retrieves requested chassis sensors and redundancy data from DBus .
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200149 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100150 * @param callback Callback for next step in gathered sensor processing
151 */
152template <typename Callback>
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200153void getChassis(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
154 Callback&& callback) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700155 BMCWEB_LOG_DEBUG << "getChassis enter";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100156 // Process response from EntityManager and extract chassis data
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700157 auto respHandler = [ callback{std::move(callback)}, SensorsAsyncResp ](
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100158 const boost::system::error_code ec, ManagedObjectsVectorType& resp) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700159 BMCWEB_LOG_DEBUG << "getChassis respHandler enter";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100160 if (ec) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700161 BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec;
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200162 SensorsAsyncResp->setErrorStatus();
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100163 return;
164 }
165 boost::container::flat_set<std::string> sensorNames;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100166
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200167 // SensorsAsyncResp->chassisId
Ed Tanousdaf36e22018-04-20 16:01:36 -0700168 bool foundChassis = false;
169 std::vector<std::string> split;
170 // Reserve space for
171 // /xyz/openbmc_project/inventory/<name>/<subname> + 3 subnames
172 split.reserve(8);
173
174 for (const auto& objDictEntry : resp) {
175 const std::string& objectPath =
176 static_cast<const std::string&>(objDictEntry.first);
177 boost::algorithm::split(split, objectPath, boost::is_any_of("/"));
178 if (split.size() < 2) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700179 BMCWEB_LOG_ERROR << "Got path that isn't long enough " << objectPath;
Ed Tanousdaf36e22018-04-20 16:01:36 -0700180 split.clear();
181 continue;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100182 }
Ed Tanousdaf36e22018-04-20 16:01:36 -0700183 const std::string& sensorName = split.end()[-1];
184 const std::string& chassisName = split.end()[-2];
185
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200186 if (chassisName != SensorsAsyncResp->chassisId) {
Ed Tanousdaf36e22018-04-20 16:01:36 -0700187 split.clear();
188 continue;
189 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700190 BMCWEB_LOG_DEBUG << "New sensor: " << sensorName;
Ed Tanousdaf36e22018-04-20 16:01:36 -0700191 foundChassis = true;
192 sensorNames.emplace(sensorName);
193 split.clear();
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100194 };
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700195 BMCWEB_LOG_DEBUG << "Found " << sensorNames.size() << " Sensor names";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100196
197 if (!foundChassis) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700198 BMCWEB_LOG_INFO << "Unable to find chassis named "
199 << SensorsAsyncResp->chassisId;
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200200 SensorsAsyncResp->res.result(boost::beast::http::status::not_found);
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100201 } else {
202 callback(sensorNames);
203 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700204 BMCWEB_LOG_DEBUG << "getChassis respHandler exit";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100205 };
206
207 // Make call to EntityManager to find all chassis objects
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700208 crow::connections::systemBus->async_method_call(
209 respHandler, "xyz.openbmc_project.EntityManager", "/",
Lewanczyk, Dawid78859542018-06-11 16:58:40 +0200210 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700211 BMCWEB_LOG_DEBUG << "getChassis exit";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100212}
213
214/**
215 * @brief Builds a json sensor representation of a sensor.
216 * @param sensorName The name of the sensor to be built
Gunnar Mills274fad52018-06-13 15:45:36 -0500217 * @param sensorType The type (temperature, fan_tach, etc) of the sensor to
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100218 * build
219 * @param interfacesDict A dictionary of the interfaces and properties of said
220 * interfaces to be built from
221 * @param sensor_json The json object to fill
222 */
223void objectInterfacesToJson(
224 const std::string& sensorName, const std::string& sensorType,
225 const boost::container::flat_map<
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700226 std::string, boost::container::flat_map<std::string, SensorVariant>>&
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100227 interfacesDict,
228 nlohmann::json& sensor_json) {
229 // We need a value interface before we can do anything with it
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700230 auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
231 if (valueIt == interfacesDict.end()) {
232 BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100233 return;
234 }
235
236 // Assume values exist as is (10^0 == 1) if no scale exists
237 int64_t scaleMultiplier = 0;
238
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700239 auto scaleIt = valueIt->second.find("Scale");
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100240 // If a scale exists, pull value as int64, and use the scaling.
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700241 if (scaleIt != valueIt->second.end()) {
242 const int64_t* int64Value = mapbox::getPtr<const int64_t>(scaleIt->second);
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100243 if (int64Value != nullptr) {
244 scaleMultiplier = *int64Value;
245 }
246 }
247
248 sensor_json["MemberId"] = sensorName;
249 sensor_json["Name"] = sensorName;
250 sensor_json["Status"]["State"] = "Enabled";
251 sensor_json["Status"]["Health"] = "OK";
252
253 // Parameter to set to override the type we get from dbus, and force it to
254 // int, regardless of what is available. This is used for schemas like fan,
255 // that require integers, not floats.
256 bool forceToInt = false;
257
258 const char* unit = "Reading";
259 if (sensorType == "temperature") {
260 unit = "ReadingCelsius";
Lewanczyk, Dawid78859542018-06-11 16:58:40 +0200261 sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100262 // TODO(ed) Documentation says that path should be type fan_tach,
263 // implementation seems to implement fan
James Feist03b5bae2018-07-06 12:08:09 -0700264 } else if (sensorType == "fan" || sensorType == "fan_tach") {
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100265 unit = "Reading";
266 sensor_json["ReadingUnits"] = "RPM";
Lewanczyk, Dawid78859542018-06-11 16:58:40 +0200267 sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100268 forceToInt = true;
269 } else if (sensorType == "voltage") {
270 unit = "ReadingVolts";
Lewanczyk, Dawid78859542018-06-11 16:58:40 +0200271 sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100272 } else {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700273 BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100274 return;
275 }
276 // Map of dbus interface name, dbus property name and redfish property_name
277 std::vector<std::tuple<const char*, const char*, const char*>> properties;
278 properties.reserve(7);
279
280 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
281 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
282 "WarningHigh", "UpperThresholdNonCritical");
283 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
284 "WarningLow", "LowerThresholdNonCritical");
285 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
286 "CriticalHigh", "UpperThresholdCritical");
287 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
288 "CriticalLow", "LowerThresholdCritical");
289
290 if (sensorType == "temperature") {
291 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
292 "MinReadingRangeTemp");
293 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
294 "MaxReadingRangeTemp");
295 } else {
296 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
297 "MinReadingRange");
298 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
299 "MaxReadingRange");
300 }
301
302 for (const std::tuple<const char*, const char*, const char*>& p :
303 properties) {
304 auto interfaceProperties = interfacesDict.find(std::get<0>(p));
305 if (interfaceProperties != interfacesDict.end()) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700306 auto valueIt = interfaceProperties->second.find(std::get<1>(p));
307 if (valueIt != interfaceProperties->second.end()) {
308 const SensorVariant& valueVariant = valueIt->second;
309 nlohmann::json& valueIt = sensor_json[std::get<2>(p)];
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700310
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100311 // Attempt to pull the int64 directly
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700312 const int64_t* int64Value = mapbox::getPtr<const int64_t>(valueVariant);
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100313
314 if (int64Value != nullptr) {
315 if (forceToInt || scaleMultiplier >= 0) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700316 valueIt = *int64Value * std::pow(10, scaleMultiplier);
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100317 } else {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700318 valueIt = *int64Value *
319 std::pow(10, static_cast<double>(scaleMultiplier));
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100320 }
321 }
322 // Attempt to pull the float directly
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700323 const double* doubleValue = mapbox::getPtr<const double>(valueVariant);
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100324
325 if (doubleValue != nullptr) {
326 if (!forceToInt) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700327 valueIt = *doubleValue *
328 std::pow(10, static_cast<double>(scaleMultiplier));
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100329 } else {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700330 valueIt = static_cast<int64_t>(*doubleValue *
331 std::pow(10, scaleMultiplier));
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100332 }
333 }
334 }
335 }
336 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700337 BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100338}
339
340/**
341 * @brief Entry point for retrieving sensors data related to requested
342 * chassis.
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200343 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100344 */
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200345void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700346 BMCWEB_LOG_DEBUG << "getChassisData enter";
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200347 auto getChassisCb = [&, SensorsAsyncResp](
348 boost::container::flat_set<std::string>&
349 sensorNames) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700350 BMCWEB_LOG_DEBUG << "getChassisCb enter";
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200351 auto getConnectionCb =
352 [&, SensorsAsyncResp, sensorNames](
353 const boost::container::flat_set<std::string>& connections) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700354 BMCWEB_LOG_DEBUG << "getConnectionCb enter";
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200355 // Get managed objects from all services exposing sensors
356 for (const std::string& connection : connections) {
357 // Response handler to process managed objects
358 auto getManagedObjectsCb = [&, SensorsAsyncResp, sensorNames](
359 const boost::system::error_code ec,
360 ManagedObjectsVectorType& resp) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700361 BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
Lewanczyk, Dawid78859542018-06-11 16:58:40 +0200362 if (ec) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700363 BMCWEB_LOG_ERROR << "getManagedObjectsCb DBUS error: " << ec;
Lewanczyk, Dawid78859542018-06-11 16:58:40 +0200364 SensorsAsyncResp->setErrorStatus();
365 return;
366 }
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200367 // Go through all objects and update response with
368 // sensor data
369 for (const auto& objDictEntry : resp) {
370 const std::string& objPath =
371 static_cast<const std::string&>(objDictEntry.first);
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700372 BMCWEB_LOG_DEBUG << "getManagedObjectsCb parsing object "
373 << objPath;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100374
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200375 std::vector<std::string> split;
376 // Reserve space for
James Feist03b5bae2018-07-06 12:08:09 -0700377 // /xyz/openbmc_project/sensors/<name>/<subname>
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200378 split.reserve(6);
379 boost::algorithm::split(split, objPath, boost::is_any_of("/"));
380 if (split.size() < 6) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700381 BMCWEB_LOG_ERROR << "Got path that isn't long enough "
382 << objPath;
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200383 continue;
384 }
385 // These indexes aren't intuitive, as boost::split puts an empty
386 // string at the beggining
387 const std::string& sensorType = split[4];
388 const std::string& sensorName = split[5];
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700389 BMCWEB_LOG_DEBUG << "sensorName " << sensorName
390 << " sensorType " << sensorType;
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200391 if (sensorNames.find(sensorName) == sensorNames.end()) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700392 BMCWEB_LOG_ERROR << sensorName << " not in sensor list ";
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200393 continue;
394 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100395
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200396 const char* fieldName = nullptr;
397 if (sensorType == "temperature") {
398 fieldName = "Temperatures";
399 } else if (sensorType == "fan" || sensorType == "fan_tach") {
400 fieldName = "Fans";
401 } else if (sensorType == "voltage") {
402 fieldName = "Voltages";
403 } else if (sensorType == "current") {
404 fieldName = "PowerSupply";
405 } else if (sensorType == "power") {
406 fieldName = "PowerSupply";
407 } else {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700408 BMCWEB_LOG_ERROR << "Unsure how to handle sensorType "
409 << sensorType;
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200410 continue;
411 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100412
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700413 nlohmann::json& tempArray =
414 SensorsAsyncResp->res.jsonValue[fieldName];
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100415
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200416 // Create the array if it doesn't yet exist
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700417 if (tempArray.is_array() == false) {
418 tempArray = nlohmann::json::array();
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200419 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100420
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700421 tempArray.push_back(
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200422 {{"@odata.id", "/redfish/v1/Chassis/" +
423 SensorsAsyncResp->chassisId +
424 "/Thermal#/" + sensorName}});
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700425 nlohmann::json& sensorJson = tempArray.back();
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200426 objectInterfacesToJson(sensorName, sensorType,
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700427 objDictEntry.second, sensorJson);
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200428 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700429 BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200430 };
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700431 crow::connections::systemBus->async_method_call(
Lewanczyk, Dawid78859542018-06-11 16:58:40 +0200432 getManagedObjectsCb, connection, "/",
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200433 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
434 };
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700435 BMCWEB_LOG_DEBUG << "getConnectionCb exit";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100436 };
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700437 // get connections and then pass it to get sensors
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200438 getConnections(SensorsAsyncResp, sensorNames, std::move(getConnectionCb));
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700439 BMCWEB_LOG_DEBUG << "getChassisCb exit";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100440 };
441
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700442 // get chassis information related to sensors
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200443 getChassis(SensorsAsyncResp, std::move(getChassisCb));
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700444 BMCWEB_LOG_DEBUG << "getChassisData exit";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100445};
446
447} // namespace redfish