blob: aa48e0d735c25d62c04f6a280fde7dec776054f7 [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
John Edward Broadbent7e860f12021-04-08 15:57:16 -070018#include <app.hpp>
Ed Tanous11ba3972022-07-11 09:50:41 -070019#include <boost/algorithm/string/classification.hpp>
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010020#include <boost/algorithm/string/split.hpp>
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010021#include <boost/range/algorithm/replace_copy_if.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070022#include <dbus_singleton.hpp>
Ed Tanous168e20c2021-12-13 14:39:53 -080023#include <dbus_utility.hpp>
Ed Tanous45ca1b82022-03-25 13:07:27 -070024#include <query.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070025#include <registries/privilege_registry.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070026#include <sdbusplus/asio/property.hpp>
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +053027#include <utils/json_utils.hpp>
Nan Zhou928fefb2022-03-28 08:45:00 -070028#include <utils/query_param.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050029
30#include <cmath>
Nan Zhoufe04d492022-06-22 17:10:41 +000031#include <iterator>
32#include <map>
33#include <set>
Ed Tanousb5a76932020-09-29 16:16:58 -070034#include <utility>
Ed Tanousabf2add2019-01-22 16:40:12 -080035#include <variant>
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010036
Ed Tanous1abe55e2018-09-05 08:30:59 -070037namespace redfish
38{
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010039
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020040namespace sensors
41{
42namespace node
43{
44static constexpr std::string_view power = "Power";
45static constexpr std::string_view sensors = "Sensors";
46static constexpr std::string_view thermal = "Thermal";
47} // namespace node
48
Ed Tanous02da7c52022-02-27 00:09:02 -080049// clang-format off
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020050namespace dbus
51{
Ed Tanous4ee8e212022-05-28 09:42:51 -070052static auto powerPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080053 "/xyz/openbmc_project/sensors/voltage",
54 "/xyz/openbmc_project/sensors/power"
55});
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000056
Ed Tanous4ee8e212022-05-28 09:42:51 -070057static auto sensorPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080058 "/xyz/openbmc_project/sensors/power",
59 "/xyz/openbmc_project/sensors/current",
60 "/xyz/openbmc_project/sensors/airflow",
Ed Tanous4e777662022-08-06 09:39:13 -070061 "/xyz/openbmc_project/sensors/humidity",
George Liue8204932021-02-01 14:42:49 +080062#ifdef BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM
Ed Tanous02da7c52022-02-27 00:09:02 -080063 "/xyz/openbmc_project/sensors/voltage",
64 "/xyz/openbmc_project/sensors/fan_tach",
65 "/xyz/openbmc_project/sensors/temperature",
66 "/xyz/openbmc_project/sensors/fan_pwm",
67 "/xyz/openbmc_project/sensors/altitude",
68 "/xyz/openbmc_project/sensors/energy",
George Liue8204932021-02-01 14:42:49 +080069#endif
Ed Tanous02da7c52022-02-27 00:09:02 -080070 "/xyz/openbmc_project/sensors/utilization"
71});
72
Ed Tanous4ee8e212022-05-28 09:42:51 -070073static auto thermalPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080074 "/xyz/openbmc_project/sensors/fan_tach",
75 "/xyz/openbmc_project/sensors/temperature",
76 "/xyz/openbmc_project/sensors/fan_pwm"
77});
78
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000079} // namespace dbus
Ed Tanous02da7c52022-02-27 00:09:02 -080080// clang-format on
81
82using sensorPair = std::pair<std::string_view, std::span<std::string_view>>;
83static constexpr std::array<sensorPair, 3> paths = {
84 {{node::power, std::span<std::string_view>(dbus::powerPaths)},
85 {node::sensors, std::span<std::string_view>(dbus::sensorPaths)},
86 {node::thermal, std::span<std::string_view>(dbus::thermalPaths)}}};
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000087
88inline const char* toReadingType(const std::string& sensorType)
89{
90 if (sensorType == "voltage")
91 {
92 return "Voltage";
93 }
94 if (sensorType == "power")
95 {
96 return "Power";
97 }
98 if (sensorType == "current")
99 {
100 return "Current";
101 }
102 if (sensorType == "fan_tach")
103 {
104 return "Rotational";
105 }
106 if (sensorType == "temperature")
107 {
108 return "Temperature";
109 }
110 if (sensorType == "fan_pwm" || sensorType == "utilization")
111 {
112 return "Percent";
113 }
Gunnar Mills5deabed2022-04-20 13:43:45 -0600114 if (sensorType == "humidity")
115 {
116 return "Humidity";
117 }
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000118 if (sensorType == "altitude")
119 {
120 return "Altitude";
121 }
122 if (sensorType == "airflow")
123 {
124 return "AirFlow";
125 }
126 if (sensorType == "energy")
127 {
128 return "EnergyJoules";
129 }
130 return "";
131}
132
133inline const char* toReadingUnits(const std::string& sensorType)
134{
135 if (sensorType == "voltage")
136 {
137 return "V";
138 }
139 if (sensorType == "power")
140 {
141 return "W";
142 }
143 if (sensorType == "current")
144 {
145 return "A";
146 }
147 if (sensorType == "fan_tach")
148 {
149 return "RPM";
150 }
151 if (sensorType == "temperature")
152 {
153 return "Cel";
154 }
Gunnar Mills5deabed2022-04-20 13:43:45 -0600155 if (sensorType == "fan_pwm" || sensorType == "utilization" ||
156 sensorType == "humidity")
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000157 {
158 return "%";
159 }
160 if (sensorType == "altitude")
161 {
162 return "m";
163 }
164 if (sensorType == "airflow")
165 {
166 return "cft_i/min";
167 }
168 if (sensorType == "energy")
169 {
170 return "J";
171 }
172 return "";
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200173}
174} // namespace sensors
175
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100176/**
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200177 * SensorsAsyncResp
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100178 * Gathers data needed for response processing after async calls are done
179 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700180class SensorsAsyncResp
181{
182 public:
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200183 using DataCompleteCb = std::function<void(
184 const boost::beast::http::status status,
Nan Zhoufe04d492022-06-22 17:10:41 +0000185 const std::map<std::string, std::string>& uriToDbus)>;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200186
187 struct SensorData
188 {
189 const std::string name;
190 std::string uri;
191 const std::string valueKey;
192 const std::string dbusPath;
193 };
194
Ed Tanous8a592812022-06-04 09:06:59 -0700195 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800196 const std::string& chassisIdIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800197 std::span<std::string_view> typesIn,
198 std::string_view subNode) :
Ed Tanous8a592812022-06-04 09:06:59 -0700199 asyncResp(asyncRespIn),
Nan Zhou928fefb2022-03-28 08:45:00 -0700200 chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode),
201 efficientExpand(false)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500202 {}
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200203
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200204 // Store extra data about sensor mapping and return it in callback
Ed Tanous8a592812022-06-04 09:06:59 -0700205 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800206 const std::string& chassisIdIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800207 std::span<std::string_view> typesIn,
208 std::string_view subNode,
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200209 DataCompleteCb&& creationComplete) :
Ed Tanous8a592812022-06-04 09:06:59 -0700210 asyncResp(asyncRespIn),
Nan Zhou928fefb2022-03-28 08:45:00 -0700211 chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode),
212 efficientExpand(false), metadata{std::vector<SensorData>()},
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200213 dataComplete{std::move(creationComplete)}
214 {}
215
Nan Zhou928fefb2022-03-28 08:45:00 -0700216 // sensor collections expand
Ed Tanous8a592812022-06-04 09:06:59 -0700217 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
Nan Zhou928fefb2022-03-28 08:45:00 -0700218 const std::string& chassisIdIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800219 const std::span<std::string_view> typesIn,
Ed Tanous8a592812022-06-04 09:06:59 -0700220 const std::string_view& subNode, bool efficientExpandIn) :
221 asyncResp(asyncRespIn),
Nan Zhou928fefb2022-03-28 08:45:00 -0700222 chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode),
Ed Tanous8a592812022-06-04 09:06:59 -0700223 efficientExpand(efficientExpandIn)
Nan Zhou928fefb2022-03-28 08:45:00 -0700224 {}
225
Ed Tanous1abe55e2018-09-05 08:30:59 -0700226 ~SensorsAsyncResp()
227 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800228 if (asyncResp->res.result() ==
229 boost::beast::http::status::internal_server_error)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700230 {
231 // Reset the json object to clear out any data that made it in
232 // before the error happened todo(ed) handle error condition with
233 // proper code
zhanghch058d1b46d2021-04-01 11:18:24 +0800234 asyncResp->res.jsonValue = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700235 }
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200236
237 if (dataComplete && metadata)
238 {
Nan Zhoufe04d492022-06-22 17:10:41 +0000239 std::map<std::string, std::string> map;
zhanghch058d1b46d2021-04-01 11:18:24 +0800240 if (asyncResp->res.result() == boost::beast::http::status::ok)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200241 {
242 for (auto& sensor : *metadata)
243 {
244 map.insert(std::make_pair(sensor.uri + sensor.valueKey,
245 sensor.dbusPath));
246 }
247 }
zhanghch058d1b46d2021-04-01 11:18:24 +0800248 dataComplete(asyncResp->res.result(), map);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200249 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700250 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100251
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800252 SensorsAsyncResp(const SensorsAsyncResp&) = delete;
253 SensorsAsyncResp(SensorsAsyncResp&&) = delete;
254 SensorsAsyncResp& operator=(const SensorsAsyncResp&) = delete;
255 SensorsAsyncResp& operator=(SensorsAsyncResp&&) = delete;
256
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200257 void addMetadata(const nlohmann::json& sensorObject,
258 const std::string& valueKey, const std::string& dbusPath)
259 {
260 if (metadata)
261 {
262 metadata->emplace_back(SensorData{sensorObject["Name"],
263 sensorObject["@odata.id"],
264 valueKey, dbusPath});
265 }
266 }
267
268 void updateUri(const std::string& name, const std::string& uri)
269 {
270 if (metadata)
271 {
272 for (auto& sensor : *metadata)
273 {
274 if (sensor.name == name)
275 {
276 sensor.uri = uri;
277 }
278 }
279 }
280 }
281
zhanghch058d1b46d2021-04-01 11:18:24 +0800282 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200283 const std::string chassisId;
Ed Tanous02da7c52022-02-27 00:09:02 -0800284 const std::span<std::string_view> types;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200285 const std::string chassisSubNode;
Nan Zhou928fefb2022-03-28 08:45:00 -0700286 const bool efficientExpand;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200287
288 private:
289 std::optional<std::vector<SensorData>> metadata;
290 DataCompleteCb dataComplete;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100291};
292
293/**
Anthony Wilsond5005492019-07-31 16:34:17 -0500294 * Possible states for physical inventory leds
295 */
296enum class LedState
297{
298 OFF,
299 ON,
300 BLINK,
301 UNKNOWN
302};
303
304/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500305 * D-Bus inventory item associated with one or more sensors.
306 */
307class InventoryItem
308{
309 public:
Ed Tanous4e23a442022-06-06 09:57:26 -0700310 explicit InventoryItem(const std::string& objPath) : objectPath(objPath)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500311 {
312 // Set inventory item name to last node of object path
George Liu28aa8de2021-02-01 15:13:30 +0800313 sdbusplus::message::object_path path(objectPath);
314 name = path.filename();
315 if (name.empty())
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500316 {
George Liu28aa8de2021-02-01 15:13:30 +0800317 BMCWEB_LOG_ERROR << "Failed to find '/' in " << objectPath;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500318 }
319 }
320
321 std::string objectPath;
322 std::string name;
Ed Tanouse05aec52022-01-25 10:28:56 -0800323 bool isPresent = true;
324 bool isFunctional = true;
325 bool isPowerSupply = false;
326 int powerSupplyEfficiencyPercent = -1;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500327 std::string manufacturer;
328 std::string model;
329 std::string partNumber;
330 std::string serialNumber;
331 std::set<std::string> sensors;
Anthony Wilsond5005492019-07-31 16:34:17 -0500332 std::string ledObjectPath;
Ed Tanouse05aec52022-01-25 10:28:56 -0800333 LedState ledState = LedState::UNKNOWN;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500334};
335
336/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530337 * @brief Get objects with connection necessary for sensors
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200338 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100339 * @param sensorNames Sensors retrieved from chassis
340 * @param callback Callback for processing gathered connections
341 */
342template <typename Callback>
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530343void getObjectsWithConnection(
Ed Tanous81ce6092020-12-17 16:54:55 +0000344 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +0000345 const std::shared_ptr<std::set<std::string>>& sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530346 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700347{
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530348 BMCWEB_LOG_DEBUG << "getObjectsWithConnection enter";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700349 const std::string path = "/xyz/openbmc_project/sensors";
350 const std::array<std::string, 1> interfaces = {
351 "xyz.openbmc_project.Sensor.Value"};
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100352
Ed Tanous1abe55e2018-09-05 08:30:59 -0700353 // Response handler for parsing objects subtree
Ed Tanous002d39b2022-05-31 08:59:27 -0700354 auto respHandler =
355 [callback{std::forward<Callback>(callback)}, sensorsAsyncResp,
356 sensorNames](const boost::system::error_code ec,
357 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530358 BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler enter";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700359 if (ec)
360 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800361 messages::internalError(sensorsAsyncResp->asyncResp->res);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530362 BMCWEB_LOG_ERROR
363 << "getObjectsWithConnection resp_handler: Dbus error " << ec;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700364 return;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100365 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100366
Ed Tanous1abe55e2018-09-05 08:30:59 -0700367 BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
368
369 // Make unique list of connections only for requested sensor types and
370 // found in the chassis
Nan Zhoufe04d492022-06-22 17:10:41 +0000371 std::set<std::string> connections;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530372 std::set<std::pair<std::string, std::string>> objectsWithConnection;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700373
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700374 BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames->size();
375 for (const std::string& tsensor : *sensorNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700376 {
377 BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor;
378 }
379
380 for (const std::pair<
381 std::string,
382 std::vector<std::pair<std::string, std::vector<std::string>>>>&
383 object : subtree)
384 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700385 if (sensorNames->find(object.first) != sensorNames->end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700386 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700387 for (const std::pair<std::string, std::vector<std::string>>&
388 objData : object.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700389 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700390 BMCWEB_LOG_DEBUG << "Adding connection: " << objData.first;
391 connections.insert(objData.first);
392 objectsWithConnection.insert(
393 std::make_pair(object.first, objData.first));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700394 }
395 }
396 }
397 BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections";
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530398 callback(std::move(connections), std::move(objectsWithConnection));
399 BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler exit";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700400 };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700401 // Make call to ObjectMapper to find all sensors objects
402 crow::connections::systemBus->async_method_call(
403 std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
404 "/xyz/openbmc_project/object_mapper",
405 "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 2, interfaces);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530406 BMCWEB_LOG_DEBUG << "getObjectsWithConnection exit";
407}
408
409/**
410 * @brief Create connections necessary for sensors
411 * @param SensorsAsyncResp Pointer to object holding response data
412 * @param sensorNames Sensors retrieved from chassis
413 * @param callback Callback for processing gathered connections
414 */
415template <typename Callback>
Nan Zhoufe04d492022-06-22 17:10:41 +0000416void getConnections(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
417 const std::shared_ptr<std::set<std::string>> sensorNames,
418 Callback&& callback)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530419{
420 auto objectsWithConnectionCb =
Nan Zhoufe04d492022-06-22 17:10:41 +0000421 [callback](const std::set<std::string>& connections,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530422 const std::set<std::pair<std::string, std::string>>&
Ed Tanous3174e4d2020-10-07 11:41:22 -0700423 /*objectsWithConnection*/) { callback(connections); };
Ed Tanous81ce6092020-12-17 16:54:55 +0000424 getObjectsWithConnection(sensorsAsyncResp, sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530425 std::move(objectsWithConnectionCb));
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100426}
427
428/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700429 * @brief Shrinks the list of sensors for processing
430 * @param SensorsAysncResp The class holding the Redfish response
431 * @param allSensors A list of all the sensors associated to the
432 * chassis element (i.e. baseboard, front panel, etc...)
433 * @param activeSensors A list that is a reduction of the incoming
434 * allSensors list. Eliminate Thermal sensors when a Power request is
435 * made, and eliminate Power sensors when a Thermal request is made.
436 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000437inline void reduceSensorList(
Ed Tanous81ce6092020-12-17 16:54:55 +0000438 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700439 const std::vector<std::string>* allSensors,
Nan Zhoufe04d492022-06-22 17:10:41 +0000440 const std::shared_ptr<std::set<std::string>>& activeSensors)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700441{
Ed Tanous81ce6092020-12-17 16:54:55 +0000442 if (sensorsAsyncResp == nullptr)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700443 {
444 return;
445 }
446 if ((allSensors == nullptr) || (activeSensors == nullptr))
447 {
448 messages::resourceNotFound(
zhanghch058d1b46d2021-04-01 11:18:24 +0800449 sensorsAsyncResp->asyncResp->res, sensorsAsyncResp->chassisSubNode,
Ed Tanous81ce6092020-12-17 16:54:55 +0000450 sensorsAsyncResp->chassisSubNode == sensors::node::thermal
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200451 ? "Temperatures"
452 : "Voltages");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700453
454 return;
455 }
456 if (allSensors->empty())
457 {
458 // Nothing to do, the activeSensors object is also empty
459 return;
460 }
461
Ed Tanous02da7c52022-02-27 00:09:02 -0800462 for (std::string_view type : sensorsAsyncResp->types)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700463 {
464 for (const std::string& sensor : *allSensors)
465 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700466 if (sensor.starts_with(type))
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700467 {
468 activeSensors->emplace(sensor);
469 }
470 }
471 }
472}
473
474/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100475 * @brief Retrieves requested chassis sensors and redundancy data from DBus .
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200476 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100477 * @param callback Callback for next step in gathered sensor processing
478 */
479template <typename Callback>
Ed Tanousb5a76932020-09-29 16:16:58 -0700480void getChassis(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700481 Callback&& callback)
482{
483 BMCWEB_LOG_DEBUG << "getChassis enter";
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500484 const std::array<const char*, 2> interfaces = {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700485 "xyz.openbmc_project.Inventory.Item.Board",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500486 "xyz.openbmc_project.Inventory.Item.Chassis"};
Ed Tanous002d39b2022-05-31 08:59:27 -0700487 auto respHandler =
488 [callback{std::forward<Callback>(callback)}, sensorsAsyncResp](
489 const boost::system::error_code ec,
490 const dbus::utility::MapperGetSubTreePathsResponse& chassisPaths) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700491 BMCWEB_LOG_DEBUG << "getChassis respHandler enter";
492 if (ec)
493 {
494 BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +0800495 messages::internalError(sensorsAsyncResp->asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700496 return;
497 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100498
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700499 const std::string* chassisPath = nullptr;
500 std::string chassisName;
501 for (const std::string& chassis : chassisPaths)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700502 {
George Liu28aa8de2021-02-01 15:13:30 +0800503 sdbusplus::message::object_path path(chassis);
504 chassisName = path.filename();
505 if (chassisName.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700506 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700507 BMCWEB_LOG_ERROR << "Failed to find '/' in " << chassis;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700508 continue;
509 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700510 if (chassisName == sensorsAsyncResp->chassisId)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700511 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700512 chassisPath = &chassis;
513 break;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700514 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700515 }
516 if (chassisPath == nullptr)
517 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800518 messages::resourceNotFound(sensorsAsyncResp->asyncResp->res,
519 "Chassis", sensorsAsyncResp->chassisId);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700520 return;
521 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700522
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700523 const std::string& chassisSubNode = sensorsAsyncResp->chassisSubNode;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200524 if (chassisSubNode == sensors::node::power)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700525 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800526 sensorsAsyncResp->asyncResp->res.jsonValue["@odata.type"] =
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700527 "#Power.v1_5_2.Power";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700528 }
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200529 else if (chassisSubNode == sensors::node::thermal)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700530 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800531 sensorsAsyncResp->asyncResp->res.jsonValue["@odata.type"] =
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700532 "#Thermal.v1_4_0.Thermal";
zhanghch058d1b46d2021-04-01 11:18:24 +0800533 sensorsAsyncResp->asyncResp->res.jsonValue["Fans"] =
534 nlohmann::json::array();
535 sensorsAsyncResp->asyncResp->res.jsonValue["Temperatures"] =
Jennifer Lee4f9a2132019-03-04 12:45:19 -0800536 nlohmann::json::array();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700537 }
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200538 else if (chassisSubNode == sensors::node::sensors)
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500539 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800540 sensorsAsyncResp->asyncResp->res.jsonValue["@odata.type"] =
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500541 "#SensorCollection.SensorCollection";
zhanghch058d1b46d2021-04-01 11:18:24 +0800542 sensorsAsyncResp->asyncResp->res.jsonValue["Description"] =
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500543 "Collection of Sensors for this Chassis";
zhanghch058d1b46d2021-04-01 11:18:24 +0800544 sensorsAsyncResp->asyncResp->res.jsonValue["Members"] =
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500545 nlohmann::json::array();
zhanghch058d1b46d2021-04-01 11:18:24 +0800546 sensorsAsyncResp->asyncResp->res.jsonValue["Members@odata.count"] =
547 0;
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500548 }
549
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200550 if (chassisSubNode != sensors::node::sensors)
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500551 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800552 sensorsAsyncResp->asyncResp->res.jsonValue["Id"] = chassisSubNode;
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500553 }
554
zhanghch058d1b46d2021-04-01 11:18:24 +0800555 sensorsAsyncResp->asyncResp->res.jsonValue["@odata.id"] =
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700556 "/redfish/v1/Chassis/" + sensorsAsyncResp->chassisId + "/" +
557 chassisSubNode;
zhanghch058d1b46d2021-04-01 11:18:24 +0800558 sensorsAsyncResp->asyncResp->res.jsonValue["Name"] = chassisSubNode;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500559 // Get the list of all sensors for this Chassis element
560 std::string sensorPath = *chassisPath + "/all_sensors";
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700561 sdbusplus::asio::getProperty<std::vector<std::string>>(
562 *crow::connections::systemBus, "xyz.openbmc_project.ObjectMapper",
563 sensorPath, "xyz.openbmc_project.Association", "endpoints",
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800564 [sensorsAsyncResp,
565 callback{std::forward<const Callback>(callback)}](
Ed Tanous271584a2019-07-09 16:24:22 -0700566 const boost::system::error_code& e,
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700567 const std::vector<std::string>& nodeSensorList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700568 if (e)
569 {
570 if (e.value() != EBADR)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700571 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700572 messages::internalError(sensorsAsyncResp->asyncResp->res);
573 return;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700574 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700575 }
Nan Zhoufe04d492022-06-22 17:10:41 +0000576 const std::shared_ptr<std::set<std::string>> culledSensorList =
577 std::make_shared<std::set<std::string>>();
Ed Tanous002d39b2022-05-31 08:59:27 -0700578 reduceSensorList(sensorsAsyncResp, &nodeSensorList,
579 culledSensorList);
580 callback(culledSensorList);
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700581 });
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100582 };
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100583
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700584 // Get the Chassis Collection
Ed Tanous1abe55e2018-09-05 08:30:59 -0700585 crow::connections::systemBus->async_method_call(
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700586 respHandler, "xyz.openbmc_project.ObjectMapper",
587 "/xyz/openbmc_project/object_mapper",
588 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Ed Tanous271584a2019-07-09 16:24:22 -0700589 "/xyz/openbmc_project/inventory", 0, interfaces);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700590 BMCWEB_LOG_DEBUG << "getChassis exit";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100591}
592
593/**
Shawn McCarneyde629b62019-03-08 10:42:51 -0600594 * @brief Finds all DBus object paths that implement ObjectManager.
595 *
596 * Creates a mapping from the associated connection name to the object path.
597 *
598 * Finds the object paths asynchronously. Invokes callback when information has
599 * been obtained.
600 *
601 * The callback must have the following signature:
602 * @code
Nan Zhoufe04d492022-06-22 17:10:41 +0000603 * callback(std::shared_ptr<std::map<std::string,std::string>> objectMgrPaths)
Shawn McCarneyde629b62019-03-08 10:42:51 -0600604 * @endcode
605 *
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700606 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyde629b62019-03-08 10:42:51 -0600607 * @param callback Callback to invoke when object paths obtained.
608 */
609template <typename Callback>
Ed Tanousb5a76932020-09-29 16:16:58 -0700610void getObjectManagerPaths(
Ed Tanous81ce6092020-12-17 16:54:55 +0000611 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Ed Tanousb5a76932020-09-29 16:16:58 -0700612 Callback&& callback)
Shawn McCarneyde629b62019-03-08 10:42:51 -0600613{
614 BMCWEB_LOG_DEBUG << "getObjectManagerPaths enter";
615 const std::array<std::string, 1> interfaces = {
616 "org.freedesktop.DBus.ObjectManager"};
617
618 // Response handler for GetSubTree DBus method
Ed Tanous002d39b2022-05-31 08:59:27 -0700619 auto respHandler =
620 [callback{std::forward<Callback>(callback)}, sensorsAsyncResp](
621 const boost::system::error_code ec,
622 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Shawn McCarneyde629b62019-03-08 10:42:51 -0600623 BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler enter";
624 if (ec)
625 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800626 messages::internalError(sensorsAsyncResp->asyncResp->res);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600627 BMCWEB_LOG_ERROR << "getObjectManagerPaths respHandler: DBus error "
628 << ec;
629 return;
630 }
631
632 // Loop over returned object paths
Nan Zhoufe04d492022-06-22 17:10:41 +0000633 std::shared_ptr<std::map<std::string, std::string>> objectMgrPaths =
634 std::make_shared<std::map<std::string, std::string>>();
Shawn McCarneyde629b62019-03-08 10:42:51 -0600635 for (const std::pair<
636 std::string,
637 std::vector<std::pair<std::string, std::vector<std::string>>>>&
638 object : subtree)
639 {
640 // Loop over connections for current object path
641 const std::string& objectPath = object.first;
642 for (const std::pair<std::string, std::vector<std::string>>&
643 objData : object.second)
644 {
645 // Add mapping from connection to object path
646 const std::string& connection = objData.first;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500647 (*objectMgrPaths)[connection] = objectPath;
Shawn McCarneyde629b62019-03-08 10:42:51 -0600648 BMCWEB_LOG_DEBUG << "Added mapping " << connection << " -> "
649 << objectPath;
650 }
651 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500652 callback(objectMgrPaths);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600653 BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler exit";
654 };
655
656 // Query mapper for all DBus object paths that implement ObjectManager
657 crow::connections::systemBus->async_method_call(
658 std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
659 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -0700660 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, interfaces);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600661 BMCWEB_LOG_DEBUG << "getObjectManagerPaths exit";
662}
663
664/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500665 * @brief Returns the Redfish State value for the specified inventory item.
666 * @param inventoryItem D-Bus inventory item associated with a sensor.
667 * @return State value for inventory item.
James Feist34dd1792019-05-17 14:10:54 -0700668 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000669inline std::string getState(const InventoryItem* inventoryItem)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500670{
671 if ((inventoryItem != nullptr) && !(inventoryItem->isPresent))
672 {
673 return "Absent";
674 }
James Feist34dd1792019-05-17 14:10:54 -0700675
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500676 return "Enabled";
677}
678
679/**
680 * @brief Returns the Redfish Health value for the specified sensor.
681 * @param sensorJson Sensor JSON object.
682 * @param interfacesDict Map of all sensor interfaces.
683 * @param inventoryItem D-Bus inventory item associated with the sensor. Will
684 * be nullptr if no associated inventory item was found.
685 * @return Health value for sensor.
686 */
Ed Tanous711ac7a2021-12-20 09:34:41 -0800687inline std::string
688 getHealth(nlohmann::json& sensorJson,
689 const dbus::utility::DBusInteracesMap& interfacesDict,
690 const InventoryItem* inventoryItem)
James Feist34dd1792019-05-17 14:10:54 -0700691{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500692 // Get current health value (if any) in the sensor JSON object. Some JSON
693 // objects contain multiple sensors (such as PowerSupplies). We want to set
694 // the overall health to be the most severe of any of the sensors.
695 std::string currentHealth;
696 auto statusIt = sensorJson.find("Status");
697 if (statusIt != sensorJson.end())
698 {
699 auto healthIt = statusIt->find("Health");
700 if (healthIt != statusIt->end())
701 {
702 std::string* health = healthIt->get_ptr<std::string*>();
703 if (health != nullptr)
704 {
705 currentHealth = *health;
706 }
707 }
708 }
709
710 // If current health in JSON object is already Critical, return that. This
711 // should override the sensor health, which might be less severe.
712 if (currentHealth == "Critical")
713 {
714 return "Critical";
715 }
716
717 // Check if sensor has critical threshold alarm
Ed Tanous711ac7a2021-12-20 09:34:41 -0800718
Ed Tanous9eb808c2022-01-25 10:19:23 -0800719 for (const auto& [interface, values] : interfacesDict)
James Feist34dd1792019-05-17 14:10:54 -0700720 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800721 if (interface == "xyz.openbmc_project.Sensor.Threshold.Critical")
James Feist34dd1792019-05-17 14:10:54 -0700722 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800723 for (const auto& [valueName, value] : values)
James Feist34dd1792019-05-17 14:10:54 -0700724 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800725 if (valueName == "CriticalAlarmHigh" ||
726 valueName == "CriticalAlarmLow")
727 {
728 const bool* asserted = std::get_if<bool>(&value);
729 if (asserted == nullptr)
730 {
731 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
732 }
733 else if (*asserted)
734 {
735 return "Critical";
736 }
737 }
James Feist34dd1792019-05-17 14:10:54 -0700738 }
739 }
740 }
741
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500742 // Check if associated inventory item is not functional
743 if ((inventoryItem != nullptr) && !(inventoryItem->isFunctional))
744 {
745 return "Critical";
746 }
747
748 // If current health in JSON object is already Warning, return that. This
749 // should override the sensor status, which might be less severe.
750 if (currentHealth == "Warning")
751 {
752 return "Warning";
753 }
754
755 // Check if sensor has warning threshold alarm
Ed Tanous9eb808c2022-01-25 10:19:23 -0800756 for (const auto& [interface, values] : interfacesDict)
James Feist34dd1792019-05-17 14:10:54 -0700757 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800758 if (interface == "xyz.openbmc_project.Sensor.Threshold.Warning")
James Feist34dd1792019-05-17 14:10:54 -0700759 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800760 for (const auto& [valueName, value] : values)
James Feist34dd1792019-05-17 14:10:54 -0700761 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800762 if (valueName == "WarningAlarmHigh" ||
763 valueName == "WarningAlarmLow")
764 {
765 const bool* asserted = std::get_if<bool>(&value);
766 if (asserted == nullptr)
767 {
768 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
769 }
770 else if (*asserted)
771 {
Ed Tanousebe4d912022-01-12 12:38:17 -0800772 return "Warning";
Ed Tanous711ac7a2021-12-20 09:34:41 -0800773 }
774 }
James Feist34dd1792019-05-17 14:10:54 -0700775 }
776 }
777 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500778
James Feist34dd1792019-05-17 14:10:54 -0700779 return "OK";
780}
781
Ed Tanous23a21a12020-07-25 04:45:05 +0000782inline void setLedState(nlohmann::json& sensorJson,
Anthony Wilsond5005492019-07-31 16:34:17 -0500783 const InventoryItem* inventoryItem)
784{
785 if (inventoryItem != nullptr && !inventoryItem->ledObjectPath.empty())
786 {
787 switch (inventoryItem->ledState)
788 {
789 case LedState::OFF:
790 sensorJson["IndicatorLED"] = "Off";
791 break;
792 case LedState::ON:
793 sensorJson["IndicatorLED"] = "Lit";
794 break;
795 case LedState::BLINK:
796 sensorJson["IndicatorLED"] = "Blinking";
797 break;
Ed Tanous23a21a12020-07-25 04:45:05 +0000798 case LedState::UNKNOWN:
Anthony Wilsond5005492019-07-31 16:34:17 -0500799 break;
800 }
801 }
802}
803
James Feist34dd1792019-05-17 14:10:54 -0700804/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100805 * @brief Builds a json sensor representation of a sensor.
806 * @param sensorName The name of the sensor to be built
Gunnar Mills274fad52018-06-13 15:45:36 -0500807 * @param sensorType The type (temperature, fan_tach, etc) of the sensor to
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100808 * build
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200809 * @param sensorsAsyncResp Sensor metadata
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100810 * @param interfacesDict A dictionary of the interfaces and properties of said
811 * interfaces to be built from
812 * @param sensor_json The json object to fill
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500813 * @param inventoryItem D-Bus inventory item associated with the sensor. Will
814 * be nullptr if no associated inventory item was found.
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100815 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000816inline void objectInterfacesToJson(
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100817 const std::string& sensorName, const std::string& sensorType,
Ed Tanousb5a76932020-09-29 16:16:58 -0700818 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Ed Tanous711ac7a2021-12-20 09:34:41 -0800819 const dbus::utility::DBusInteracesMap& interfacesDict,
Ed Tanous81ce6092020-12-17 16:54:55 +0000820 nlohmann::json& sensorJson, InventoryItem* inventoryItem)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700821{
Ed Tanous1abe55e2018-09-05 08:30:59 -0700822 // Assume values exist as is (10^0 == 1) if no scale exists
823 int64_t scaleMultiplier = 0;
Ed Tanous9eb808c2022-01-25 10:19:23 -0800824 for (const auto& [interface, values] : interfacesDict)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700825 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800826 if (interface == "xyz.openbmc_project.Sensor.Value")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700827 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800828 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -0800829 {
830 if (valueName == "Scale")
831 {
832 const int64_t* int64Value = std::get_if<int64_t>(&value);
833 if (int64Value != nullptr)
834 {
835 scaleMultiplier = *int64Value;
836 }
837 }
838 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100839 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100840 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700841
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200842 if (sensorsAsyncResp->chassisSubNode == sensors::node::sensors)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500843 {
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500844 // For sensors in SensorCollection we set Id instead of MemberId,
845 // including power sensors.
Ed Tanous81ce6092020-12-17 16:54:55 +0000846 sensorJson["Id"] = sensorName;
847 sensorJson["Name"] = boost::replace_all_copy(sensorName, "_", " ");
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500848 }
849 else if (sensorType != "power")
850 {
851 // Set MemberId and Name for non-power sensors. For PowerSupplies and
852 // PowerControl, those properties have more general values because
853 // multiple sensors can be stored in the same JSON object.
Ed Tanous81ce6092020-12-17 16:54:55 +0000854 sensorJson["MemberId"] = sensorName;
855 sensorJson["Name"] = boost::replace_all_copy(sensorName, "_", " ");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500856 }
Ed Tanouse742b6c2019-05-03 15:06:53 -0700857
Ed Tanous81ce6092020-12-17 16:54:55 +0000858 sensorJson["Status"]["State"] = getState(inventoryItem);
859 sensorJson["Status"]["Health"] =
860 getHealth(sensorJson, interfacesDict, inventoryItem);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700861
862 // Parameter to set to override the type we get from dbus, and force it to
863 // int, regardless of what is available. This is used for schemas like fan,
864 // that require integers, not floats.
865 bool forceToInt = false;
866
Anthony Wilson3929aca2019-07-19 15:42:33 -0500867 nlohmann::json::json_pointer unit("/Reading");
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200868 if (sensorsAsyncResp->chassisSubNode == sensors::node::sensors)
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500869 {
Shounak Mitra2a4ba192022-06-01 23:34:12 +0000870 sensorJson["@odata.type"] = "#Sensor.v1_2_0.Sensor";
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000871
872 const std::string& readingType = sensors::toReadingType(sensorType);
873 if (readingType.empty())
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500874 {
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000875 BMCWEB_LOG_ERROR << "Redfish cannot map reading type for "
876 << sensorType;
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500877 }
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000878 else
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500879 {
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000880 sensorJson["ReadingType"] = readingType;
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500881 }
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000882
883 const std::string& readingUnits = sensors::toReadingUnits(sensorType);
884 if (readingUnits.empty())
Adrian Ambrożewiczf8ede152020-06-02 13:26:33 +0200885 {
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000886 BMCWEB_LOG_ERROR << "Redfish cannot map reading unit for "
887 << sensorType;
888 }
889 else
890 {
891 sensorJson["ReadingUnits"] = readingUnits;
Adrian Ambrożewiczf8ede152020-06-02 13:26:33 +0200892 }
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500893 }
894 else if (sensorType == "temperature")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700895 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500896 unit = "/ReadingCelsius"_json_pointer;
Ed Tanous81ce6092020-12-17 16:54:55 +0000897 sensorJson["@odata.type"] = "#Thermal.v1_3_0.Temperature";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700898 // TODO(ed) Documentation says that path should be type fan_tach,
899 // implementation seems to implement fan
900 }
901 else if (sensorType == "fan" || sensorType == "fan_tach")
902 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500903 unit = "/Reading"_json_pointer;
Ed Tanous81ce6092020-12-17 16:54:55 +0000904 sensorJson["ReadingUnits"] = "RPM";
905 sensorJson["@odata.type"] = "#Thermal.v1_3_0.Fan";
906 setLedState(sensorJson, inventoryItem);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700907 forceToInt = true;
908 }
Ed Tanous6f6d0d32018-10-12 11:16:43 -0700909 else if (sensorType == "fan_pwm")
910 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500911 unit = "/Reading"_json_pointer;
Ed Tanous81ce6092020-12-17 16:54:55 +0000912 sensorJson["ReadingUnits"] = "Percent";
913 sensorJson["@odata.type"] = "#Thermal.v1_3_0.Fan";
914 setLedState(sensorJson, inventoryItem);
Ed Tanous6f6d0d32018-10-12 11:16:43 -0700915 forceToInt = true;
916 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700917 else if (sensorType == "voltage")
918 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500919 unit = "/ReadingVolts"_json_pointer;
Ed Tanous81ce6092020-12-17 16:54:55 +0000920 sensorJson["@odata.type"] = "#Power.v1_0_0.Voltage";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700921 }
Ed Tanous2474adf2018-09-05 16:31:16 -0700922 else if (sensorType == "power")
923 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700924 std::string sensorNameLower =
925 boost::algorithm::to_lower_copy(sensorName);
926
Ed Tanous55f79e62022-01-25 11:26:16 -0800927 if (sensorName == "total_power")
Eddie James028f7eb2019-05-17 21:24:36 +0000928 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000929 sensorJson["@odata.type"] = "#Power.v1_0_0.PowerControl";
Gunnar Mills7ab06f42019-07-02 13:07:16 -0500930 // Put multiple "sensors" into a single PowerControl, so have
931 // generic names for MemberId and Name. Follows Redfish mockup.
Ed Tanous81ce6092020-12-17 16:54:55 +0000932 sensorJson["MemberId"] = "0";
933 sensorJson["Name"] = "Chassis Power Control";
Anthony Wilson3929aca2019-07-19 15:42:33 -0500934 unit = "/PowerConsumedWatts"_json_pointer;
Eddie James028f7eb2019-05-17 21:24:36 +0000935 }
936 else if (sensorNameLower.find("input") != std::string::npos)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700937 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500938 unit = "/PowerInputWatts"_json_pointer;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700939 }
940 else
941 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500942 unit = "/PowerOutputWatts"_json_pointer;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700943 }
Ed Tanous2474adf2018-09-05 16:31:16 -0700944 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700945 else
946 {
947 BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
948 return;
949 }
950 // Map of dbus interface name, dbus property name and redfish property_name
Anthony Wilson3929aca2019-07-19 15:42:33 -0500951 std::vector<
952 std::tuple<const char*, const char*, nlohmann::json::json_pointer>>
953 properties;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700954 properties.reserve(7);
955
956 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600957
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200958 if (sensorsAsyncResp->chassisSubNode == sensors::node::sensors)
Anthony Wilson3929aca2019-07-19 15:42:33 -0500959 {
960 properties.emplace_back(
961 "xyz.openbmc_project.Sensor.Threshold.Warning", "WarningHigh",
962 "/Thresholds/UpperCaution/Reading"_json_pointer);
963 properties.emplace_back(
964 "xyz.openbmc_project.Sensor.Threshold.Warning", "WarningLow",
965 "/Thresholds/LowerCaution/Reading"_json_pointer);
966 properties.emplace_back(
967 "xyz.openbmc_project.Sensor.Threshold.Critical", "CriticalHigh",
968 "/Thresholds/UpperCritical/Reading"_json_pointer);
969 properties.emplace_back(
970 "xyz.openbmc_project.Sensor.Threshold.Critical", "CriticalLow",
971 "/Thresholds/LowerCritical/Reading"_json_pointer);
972 }
973 else if (sensorType != "power")
Shawn McCarneyde629b62019-03-08 10:42:51 -0600974 {
975 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500976 "WarningHigh",
977 "/UpperThresholdNonCritical"_json_pointer);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600978 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500979 "WarningLow",
980 "/LowerThresholdNonCritical"_json_pointer);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600981 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500982 "CriticalHigh",
983 "/UpperThresholdCritical"_json_pointer);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600984 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500985 "CriticalLow",
986 "/LowerThresholdCritical"_json_pointer);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600987 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700988
Ed Tanous2474adf2018-09-05 16:31:16 -0700989 // TODO Need to get UpperThresholdFatal and LowerThresholdFatal
990
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200991 if (sensorsAsyncResp->chassisSubNode == sensors::node::sensors)
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500992 {
993 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500994 "/ReadingRangeMin"_json_pointer);
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500995 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500996 "/ReadingRangeMax"_json_pointer);
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500997 }
998 else if (sensorType == "temperature")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700999 {
1000 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -05001001 "/MinReadingRangeTemp"_json_pointer);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001002 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -05001003 "/MaxReadingRangeTemp"_json_pointer);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001004 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001005 else if (sensorType != "power")
Ed Tanous1abe55e2018-09-05 08:30:59 -07001006 {
1007 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -05001008 "/MinReadingRange"_json_pointer);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001009 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -05001010 "/MaxReadingRange"_json_pointer);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001011 }
1012
Anthony Wilson3929aca2019-07-19 15:42:33 -05001013 for (const std::tuple<const char*, const char*,
1014 nlohmann::json::json_pointer>& p : properties)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001015 {
Ed Tanous55f79e62022-01-25 11:26:16 -08001016 for (const auto& [interface, values] : interfacesDict)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001017 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001018 if (interface != std::get<0>(p))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001019 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001020 continue;
1021 }
Ed Tanous55f79e62022-01-25 11:26:16 -08001022 for (const auto& [valueName, valueVariant] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001023 {
1024 if (valueName != std::get<1>(p))
1025 {
1026 continue;
1027 }
Anthony Wilson3929aca2019-07-19 15:42:33 -05001028
1029 // The property we want to set may be nested json, so use
1030 // a json_pointer for easy indexing into the json structure.
1031 const nlohmann::json::json_pointer& key = std::get<2>(p);
1032
Ed Tanous1abe55e2018-09-05 08:30:59 -07001033 // Attempt to pull the int64 directly
Ed Tanousabf2add2019-01-22 16:40:12 -08001034 const int64_t* int64Value = std::get_if<int64_t>(&valueVariant);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001035
Ed Tanousabf2add2019-01-22 16:40:12 -08001036 const double* doubleValue = std::get_if<double>(&valueVariant);
Eddie James028f7eb2019-05-17 21:24:36 +00001037 const uint32_t* uValue = std::get_if<uint32_t>(&valueVariant);
Ed Tanous6f6d0d32018-10-12 11:16:43 -07001038 double temp = 0.0;
1039 if (int64Value != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001040 {
Ed Tanous271584a2019-07-09 16:24:22 -07001041 temp = static_cast<double>(*int64Value);
Ed Tanous6f6d0d32018-10-12 11:16:43 -07001042 }
1043 else if (doubleValue != nullptr)
1044 {
1045 temp = *doubleValue;
1046 }
Eddie James028f7eb2019-05-17 21:24:36 +00001047 else if (uValue != nullptr)
1048 {
1049 temp = *uValue;
1050 }
Ed Tanous6f6d0d32018-10-12 11:16:43 -07001051 else
1052 {
1053 BMCWEB_LOG_ERROR
1054 << "Got value interface that wasn't int or double";
1055 continue;
1056 }
1057 temp = temp * std::pow(10, scaleMultiplier);
1058 if (forceToInt)
1059 {
Ed Tanous81ce6092020-12-17 16:54:55 +00001060 sensorJson[key] = static_cast<int64_t>(temp);
Ed Tanous6f6d0d32018-10-12 11:16:43 -07001061 }
1062 else
1063 {
Ed Tanous81ce6092020-12-17 16:54:55 +00001064 sensorJson[key] = temp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001065 }
1066 }
1067 }
1068 }
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02001069
Ed Tanous81ce6092020-12-17 16:54:55 +00001070 sensorsAsyncResp->addMetadata(sensorJson, unit.to_string(),
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02001071 "/xyz/openbmc_project/sensors/" + sensorType +
1072 "/" + sensorName);
1073
Ed Tanous1abe55e2018-09-05 08:30:59 -07001074 BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01001075}
1076
Ed Tanousb5a76932020-09-29 16:16:58 -07001077inline void populateFanRedundancy(
1078 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
James Feist8bd25cc2019-03-15 15:14:00 -07001079{
1080 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001081 [sensorsAsyncResp](
1082 const boost::system::error_code ec,
1083 const dbus::utility::MapperGetSubTreeResponse& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001084 if (ec)
1085 {
1086 return; // don't have to have this interface
1087 }
1088 for (const std::pair<
1089 std::string,
1090 std::vector<std::pair<std::string, std::vector<std::string>>>>&
1091 pathPair : resp)
1092 {
1093 const std::string& path = pathPair.first;
1094 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1095 objDict = pathPair.second;
1096 if (objDict.empty())
James Feist8bd25cc2019-03-15 15:14:00 -07001097 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001098 continue; // this should be impossible
James Feist8bd25cc2019-03-15 15:14:00 -07001099 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001100
1101 const std::string& owner = objDict.begin()->first;
1102 sdbusplus::asio::getProperty<std::vector<std::string>>(
1103 *crow::connections::systemBus,
1104 "xyz.openbmc_project.ObjectMapper", path + "/chassis",
1105 "xyz.openbmc_project.Association", "endpoints",
1106 [path, owner,
1107 sensorsAsyncResp](const boost::system::error_code e,
1108 const std::vector<std::string>& endpoints) {
1109 if (e)
James Feist8bd25cc2019-03-15 15:14:00 -07001110 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001111 return; // if they don't have an association we
1112 // can't tell what chassis is
James Feist8bd25cc2019-03-15 15:14:00 -07001113 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001114 auto found =
1115 std::find_if(endpoints.begin(), endpoints.end(),
1116 [sensorsAsyncResp](const std::string& entry) {
1117 return entry.find(sensorsAsyncResp->chassisId) !=
1118 std::string::npos;
1119 });
James Feist8bd25cc2019-03-15 15:14:00 -07001120
Ed Tanous002d39b2022-05-31 08:59:27 -07001121 if (found == endpoints.end())
1122 {
1123 return;
1124 }
1125 crow::connections::systemBus->async_method_call(
1126 [path, sensorsAsyncResp](
1127 const boost::system::error_code& err,
Nan Zhoufe04d492022-06-22 17:10:41 +00001128 const std::map<std::string,
1129 dbus::utility::DbusVariantType>& ret) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001130 if (err)
1131 {
1132 return; // don't have to have this
1133 // interface
1134 }
1135 auto findFailures = ret.find("AllowedFailures");
1136 auto findCollection = ret.find("Collection");
1137 auto findStatus = ret.find("Status");
1138
1139 if (findFailures == ret.end() ||
1140 findCollection == ret.end() || findStatus == ret.end())
1141 {
1142 BMCWEB_LOG_ERROR << "Invalid redundancy interface";
1143 messages::internalError(
1144 sensorsAsyncResp->asyncResp->res);
1145 return;
1146 }
1147
1148 const uint8_t* allowedFailures =
1149 std::get_if<uint8_t>(&(findFailures->second));
1150 const std::vector<std::string>* collection =
1151 std::get_if<std::vector<std::string>>(
1152 &(findCollection->second));
1153 const std::string* status =
1154 std::get_if<std::string>(&(findStatus->second));
1155
1156 if (allowedFailures == nullptr || collection == nullptr ||
1157 status == nullptr)
1158 {
1159
1160 BMCWEB_LOG_ERROR
1161 << "Invalid redundancy interface types";
1162 messages::internalError(
1163 sensorsAsyncResp->asyncResp->res);
1164 return;
1165 }
1166 sdbusplus::message::object_path objectPath(path);
1167 std::string name = objectPath.filename();
1168 if (name.empty())
1169 {
1170 // this should be impossible
1171 messages::internalError(
1172 sensorsAsyncResp->asyncResp->res);
1173 return;
1174 }
1175 std::replace(name.begin(), name.end(), '_', ' ');
1176
1177 std::string health;
1178
Ed Tanous11ba3972022-07-11 09:50:41 -07001179 if (status->ends_with("Full"))
Ed Tanous002d39b2022-05-31 08:59:27 -07001180 {
1181 health = "OK";
1182 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001183 else if (status->ends_with("Degraded"))
Ed Tanous002d39b2022-05-31 08:59:27 -07001184 {
1185 health = "Warning";
1186 }
1187 else
1188 {
1189 health = "Critical";
1190 }
1191 nlohmann::json::array_t redfishCollection;
1192 const auto& fanRedfish =
1193 sensorsAsyncResp->asyncResp->res.jsonValue["Fans"];
1194 for (const std::string& item : *collection)
1195 {
Ed Tanous8a592812022-06-04 09:06:59 -07001196 sdbusplus::message::object_path itemPath(item);
1197 std::string itemName = itemPath.filename();
Ed Tanous002d39b2022-05-31 08:59:27 -07001198 if (itemName.empty())
James Feist8bd25cc2019-03-15 15:14:00 -07001199 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001200 continue;
James Feist8bd25cc2019-03-15 15:14:00 -07001201 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001202 /*
1203 todo(ed): merge patch that fixes the names
1204 std::replace(itemName.begin(),
1205 itemName.end(), '_', ' ');*/
1206 auto schemaItem =
1207 std::find_if(fanRedfish.begin(), fanRedfish.end(),
1208 [itemName](const nlohmann::json& fan) {
1209 return fan["MemberId"] == itemName;
James Feist8bd25cc2019-03-15 15:14:00 -07001210 });
Ed Tanous002d39b2022-05-31 08:59:27 -07001211 if (schemaItem != fanRedfish.end())
James Feist8bd25cc2019-03-15 15:14:00 -07001212 {
Ed Tanous8a592812022-06-04 09:06:59 -07001213 nlohmann::json::object_t collectionId;
1214 collectionId["@odata.id"] =
Ed Tanous002d39b2022-05-31 08:59:27 -07001215 (*schemaItem)["@odata.id"];
1216 redfishCollection.emplace_back(
Ed Tanous8a592812022-06-04 09:06:59 -07001217 std::move(collectionId));
Ed Tanous002d39b2022-05-31 08:59:27 -07001218 }
1219 else
1220 {
1221 BMCWEB_LOG_ERROR << "failed to find fan in schema";
1222 messages::internalError(
1223 sensorsAsyncResp->asyncResp->res);
James Feist8bd25cc2019-03-15 15:14:00 -07001224 return;
1225 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001226 }
James Feist8bd25cc2019-03-15 15:14:00 -07001227
Ed Tanous002d39b2022-05-31 08:59:27 -07001228 size_t minNumNeeded =
1229 collection->empty()
1230 ? 0
1231 : collection->size() - *allowedFailures;
1232 nlohmann::json& jResp = sensorsAsyncResp->asyncResp->res
1233 .jsonValue["Redundancy"];
James Feist8bd25cc2019-03-15 15:14:00 -07001234
Ed Tanous002d39b2022-05-31 08:59:27 -07001235 nlohmann::json::object_t redundancy;
1236 redundancy["@odata.id"] =
1237 "/redfish/v1/Chassis/" + sensorsAsyncResp->chassisId +
1238 "/" + sensorsAsyncResp->chassisSubNode +
1239 "#/Redundancy/" + std::to_string(jResp.size());
1240 redundancy["@odata.type"] = "#Redundancy.v1_3_2.Redundancy";
1241 redundancy["MinNumNeeded"] = minNumNeeded;
1242 redundancy["MemberId"] = name;
1243 redundancy["Mode"] = "N+m";
1244 redundancy["Name"] = name;
1245 redundancy["RedundancySet"] = redfishCollection;
1246 redundancy["Status"]["Health"] = health;
1247 redundancy["Status"]["State"] = "Enabled";
James Feist8bd25cc2019-03-15 15:14:00 -07001248
Ed Tanous002d39b2022-05-31 08:59:27 -07001249 jResp.push_back(std::move(redundancy));
1250 },
1251 owner, path, "org.freedesktop.DBus.Properties", "GetAll",
1252 "xyz.openbmc_project.Control.FanRedundancy");
1253 });
1254 }
James Feist8bd25cc2019-03-15 15:14:00 -07001255 },
1256 "xyz.openbmc_project.ObjectMapper",
1257 "/xyz/openbmc_project/object_mapper",
1258 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1259 "/xyz/openbmc_project/control", 2,
1260 std::array<const char*, 1>{
1261 "xyz.openbmc_project.Control.FanRedundancy"});
1262}
1263
Ed Tanousb5a76932020-09-29 16:16:58 -07001264inline void
Ed Tanous81ce6092020-12-17 16:54:55 +00001265 sortJSONResponse(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001266{
zhanghch058d1b46d2021-04-01 11:18:24 +08001267 nlohmann::json& response = sensorsAsyncResp->asyncResp->res.jsonValue;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001268 std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
Ed Tanous81ce6092020-12-17 16:54:55 +00001269 if (sensorsAsyncResp->chassisSubNode == sensors::node::power)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001270 {
1271 sensorHeaders = {"Voltages", "PowerSupplies"};
1272 }
1273 for (const std::string& sensorGroup : sensorHeaders)
1274 {
1275 nlohmann::json::iterator entry = response.find(sensorGroup);
1276 if (entry != response.end())
1277 {
1278 std::sort(entry->begin(), entry->end(),
Ed Tanous02cad962022-06-30 16:50:15 -07001279 [](const nlohmann::json& c1, const nlohmann::json& c2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001280 return c1["Name"] < c2["Name"];
1281 });
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001282
1283 // add the index counts to the end of each entry
1284 size_t count = 0;
1285 for (nlohmann::json& sensorJson : *entry)
1286 {
1287 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
1288 if (odata == sensorJson.end())
1289 {
1290 continue;
1291 }
1292 std::string* value = odata->get_ptr<std::string*>();
1293 if (value != nullptr)
1294 {
1295 *value += std::to_string(count);
1296 count++;
Ed Tanous81ce6092020-12-17 16:54:55 +00001297 sensorsAsyncResp->updateUri(sensorJson["Name"], *value);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001298 }
1299 }
1300 }
1301 }
1302}
1303
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01001304/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001305 * @brief Finds the inventory item with the specified object path.
1306 * @param inventoryItems D-Bus inventory items associated with sensors.
1307 * @param invItemObjPath D-Bus object path of inventory item.
1308 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001309 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001310inline InventoryItem* findInventoryItem(
Ed Tanousb5a76932020-09-29 16:16:58 -07001311 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001312 const std::string& invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001313{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001314 for (InventoryItem& inventoryItem : *inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001315 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001316 if (inventoryItem.objectPath == invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001317 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001318 return &inventoryItem;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001319 }
1320 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001321 return nullptr;
1322}
1323
1324/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001325 * @brief Finds the inventory item associated with the specified sensor.
1326 * @param inventoryItems D-Bus inventory items associated with sensors.
1327 * @param sensorObjPath D-Bus object path of sensor.
1328 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001329 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001330inline InventoryItem* findInventoryItemForSensor(
Ed Tanousb5a76932020-09-29 16:16:58 -07001331 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001332 const std::string& sensorObjPath)
1333{
1334 for (InventoryItem& inventoryItem : *inventoryItems)
1335 {
1336 if (inventoryItem.sensors.count(sensorObjPath) > 0)
1337 {
1338 return &inventoryItem;
1339 }
1340 }
1341 return nullptr;
1342}
1343
1344/**
Anthony Wilsond5005492019-07-31 16:34:17 -05001345 * @brief Finds the inventory item associated with the specified led path.
1346 * @param inventoryItems D-Bus inventory items associated with sensors.
1347 * @param ledObjPath D-Bus object path of led.
1348 * @return Inventory item within vector, or nullptr if no match found.
1349 */
1350inline InventoryItem*
1351 findInventoryItemForLed(std::vector<InventoryItem>& inventoryItems,
1352 const std::string& ledObjPath)
1353{
1354 for (InventoryItem& inventoryItem : inventoryItems)
1355 {
1356 if (inventoryItem.ledObjectPath == ledObjPath)
1357 {
1358 return &inventoryItem;
1359 }
1360 }
1361 return nullptr;
1362}
1363
1364/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001365 * @brief Adds inventory item and associated sensor to specified vector.
1366 *
1367 * Adds a new InventoryItem to the vector if necessary. Searches for an
1368 * existing InventoryItem with the specified object path. If not found, one is
1369 * added to the vector.
1370 *
1371 * Next, the specified sensor is added to the set of sensors associated with the
1372 * InventoryItem.
1373 *
1374 * @param inventoryItems D-Bus inventory items associated with sensors.
1375 * @param invItemObjPath D-Bus object path of inventory item.
1376 * @param sensorObjPath D-Bus object path of sensor
1377 */
Ed Tanousb5a76932020-09-29 16:16:58 -07001378inline void addInventoryItem(
1379 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
1380 const std::string& invItemObjPath, const std::string& sensorObjPath)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001381{
1382 // Look for inventory item in vector
1383 InventoryItem* inventoryItem =
1384 findInventoryItem(inventoryItems, invItemObjPath);
1385
1386 // If inventory item doesn't exist in vector, add it
1387 if (inventoryItem == nullptr)
1388 {
1389 inventoryItems->emplace_back(invItemObjPath);
1390 inventoryItem = &(inventoryItems->back());
1391 }
1392
1393 // Add sensor to set of sensors associated with inventory item
1394 inventoryItem->sensors.emplace(sensorObjPath);
1395}
1396
1397/**
1398 * @brief Stores D-Bus data in the specified inventory item.
1399 *
1400 * Finds D-Bus data in the specified map of interfaces. Stores the data in the
1401 * specified InventoryItem.
1402 *
1403 * This data is later used to provide sensor property values in the JSON
1404 * response.
1405 *
1406 * @param inventoryItem Inventory item where data will be stored.
1407 * @param interfacesDict Map containing D-Bus interfaces and their properties
1408 * for the specified inventory item.
1409 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001410inline void storeInventoryItemData(
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001411 InventoryItem& inventoryItem,
Ed Tanous711ac7a2021-12-20 09:34:41 -08001412 const dbus::utility::DBusInteracesMap& interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001413{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001414 // Get properties from Inventory.Item interface
Ed Tanous711ac7a2021-12-20 09:34:41 -08001415
Ed Tanous9eb808c2022-01-25 10:19:23 -08001416 for (const auto& [interface, values] : interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001417 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001418 if (interface == "xyz.openbmc_project.Inventory.Item")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001419 {
Ed Tanous9eb808c2022-01-25 10:19:23 -08001420 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001421 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001422 if (name == "Present")
1423 {
1424 const bool* value = std::get_if<bool>(&dbusValue);
1425 if (value != nullptr)
1426 {
1427 inventoryItem.isPresent = *value;
1428 }
1429 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001430 }
1431 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001432 // Check if Inventory.Item.PowerSupply interface is present
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001433
Ed Tanous711ac7a2021-12-20 09:34:41 -08001434 if (interface == "xyz.openbmc_project.Inventory.Item.PowerSupply")
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001435 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001436 inventoryItem.isPowerSupply = true;
1437 }
1438
1439 // Get properties from Inventory.Decorator.Asset interface
1440 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
1441 {
Ed Tanous9eb808c2022-01-25 10:19:23 -08001442 for (const auto& [name, dbusValue] : values)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001443 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001444 if (name == "Manufacturer")
1445 {
1446 const std::string* value =
1447 std::get_if<std::string>(&dbusValue);
1448 if (value != nullptr)
1449 {
1450 inventoryItem.manufacturer = *value;
1451 }
1452 }
1453 if (name == "Model")
1454 {
1455 const std::string* value =
1456 std::get_if<std::string>(&dbusValue);
1457 if (value != nullptr)
1458 {
1459 inventoryItem.model = *value;
1460 }
1461 }
1462 if (name == "SerialNumber")
1463 {
1464 const std::string* value =
1465 std::get_if<std::string>(&dbusValue);
1466 if (value != nullptr)
1467 {
1468 inventoryItem.serialNumber = *value;
1469 }
1470 }
1471 if (name == "PartNumber")
1472 {
1473 const std::string* value =
1474 std::get_if<std::string>(&dbusValue);
1475 if (value != nullptr)
1476 {
1477 inventoryItem.partNumber = *value;
1478 }
1479 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001480 }
1481 }
1482
Ed Tanous711ac7a2021-12-20 09:34:41 -08001483 if (interface ==
1484 "xyz.openbmc_project.State.Decorator.OperationalStatus")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001485 {
Ed Tanous9eb808c2022-01-25 10:19:23 -08001486 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001487 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001488 if (name == "Functional")
1489 {
1490 const bool* value = std::get_if<bool>(&dbusValue);
1491 if (value != nullptr)
1492 {
1493 inventoryItem.isFunctional = *value;
1494 }
1495 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001496 }
1497 }
1498 }
1499}
1500
1501/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001502 * @brief Gets D-Bus data for inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001503 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001504 * Uses the specified connections (services) to obtain D-Bus data for inventory
1505 * items associated with sensors. Stores the resulting data in the
1506 * inventoryItems vector.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001507 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001508 * This data is later used to provide sensor property values in the JSON
1509 * response.
1510 *
1511 * Finds the inventory item data asynchronously. Invokes callback when data has
1512 * been obtained.
1513 *
1514 * The callback must have the following signature:
1515 * @code
Anthony Wilsond5005492019-07-31 16:34:17 -05001516 * callback(void)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001517 * @endcode
1518 *
1519 * This function is called recursively, obtaining data asynchronously from one
1520 * connection in each call. This ensures the callback is not invoked until the
1521 * last asynchronous function has completed.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001522 *
1523 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001524 * @param inventoryItems D-Bus inventory items associated with sensors.
1525 * @param invConnections Connections that provide data for the inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001526 * @param objectMgrPaths Mappings from connection name to DBus object path that
1527 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001528 * @param callback Callback to invoke when inventory data has been obtained.
1529 * @param invConnectionsIndex Current index in invConnections. Only specified
1530 * in recursive calls to this function.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001531 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001532template <typename Callback>
1533static void getInventoryItemsData(
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001534 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001535 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001536 std::shared_ptr<std::set<std::string>> invConnections,
1537 std::shared_ptr<std::map<std::string, std::string>> objectMgrPaths,
Ed Tanous271584a2019-07-09 16:24:22 -07001538 Callback&& callback, size_t invConnectionsIndex = 0)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001539{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001540 BMCWEB_LOG_DEBUG << "getInventoryItemsData enter";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001541
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001542 // If no more connections left, call callback
1543 if (invConnectionsIndex >= invConnections->size())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001544 {
Anthony Wilsond5005492019-07-31 16:34:17 -05001545 callback();
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001546 BMCWEB_LOG_DEBUG << "getInventoryItemsData exit";
1547 return;
1548 }
1549
1550 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +00001551 auto it = invConnections->begin();
1552 std::advance(it, invConnectionsIndex);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001553 if (it != invConnections->end())
1554 {
1555 const std::string& invConnection = *it;
1556
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001557 // Response handler for GetManagedObjects
Ed Tanous002d39b2022-05-31 08:59:27 -07001558 auto respHandler =
1559 [sensorsAsyncResp, inventoryItems, invConnections, objectMgrPaths,
Ed Tanous02cad962022-06-30 16:50:15 -07001560 callback{std::forward<Callback>(callback)}, invConnectionsIndex](
1561 const boost::system::error_code ec,
1562 const dbus::utility::ManagedObjectType& resp) {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001563 BMCWEB_LOG_DEBUG << "getInventoryItemsData respHandler enter";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001564 if (ec)
1565 {
1566 BMCWEB_LOG_ERROR
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001567 << "getInventoryItemsData respHandler DBus error " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +08001568 messages::internalError(sensorsAsyncResp->asyncResp->res);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001569 return;
1570 }
1571
1572 // Loop through returned object paths
1573 for (const auto& objDictEntry : resp)
1574 {
1575 const std::string& objPath =
1576 static_cast<const std::string&>(objDictEntry.first);
1577
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001578 // If this object path is one of the specified inventory items
1579 InventoryItem* inventoryItem =
1580 findInventoryItem(inventoryItems, objPath);
1581 if (inventoryItem != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001582 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001583 // Store inventory data in InventoryItem
1584 storeInventoryItemData(*inventoryItem, objDictEntry.second);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001585 }
1586 }
1587
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001588 // Recurse to get inventory item data from next connection
1589 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1590 invConnections, objectMgrPaths,
1591 std::move(callback), invConnectionsIndex + 1);
1592
1593 BMCWEB_LOG_DEBUG << "getInventoryItemsData respHandler exit";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001594 };
1595
1596 // Find DBus object path that implements ObjectManager for the current
1597 // connection. If no mapping found, default to "/".
1598 auto iter = objectMgrPaths->find(invConnection);
1599 const std::string& objectMgrPath =
1600 (iter != objectMgrPaths->end()) ? iter->second : "/";
1601 BMCWEB_LOG_DEBUG << "ObjectManager path for " << invConnection << " is "
1602 << objectMgrPath;
1603
1604 // Get all object paths and their interfaces for current connection
1605 crow::connections::systemBus->async_method_call(
1606 std::move(respHandler), invConnection, objectMgrPath,
1607 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1608 }
1609
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001610 BMCWEB_LOG_DEBUG << "getInventoryItemsData exit";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001611}
1612
1613/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001614 * @brief Gets connections that provide D-Bus data for inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001615 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001616 * Gets the D-Bus connections (services) that provide data for the inventory
1617 * items that are associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001618 *
1619 * Finds the connections asynchronously. Invokes callback when information has
1620 * been obtained.
1621 *
1622 * The callback must have the following signature:
1623 * @code
Nan Zhoufe04d492022-06-22 17:10:41 +00001624 * callback(std::shared_ptr<std::set<std::string>> invConnections)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001625 * @endcode
1626 *
1627 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001628 * @param inventoryItems D-Bus inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001629 * @param callback Callback to invoke when connections have been obtained.
1630 */
1631template <typename Callback>
1632static void getInventoryItemsConnections(
Ed Tanousb5a76932020-09-29 16:16:58 -07001633 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1634 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001635 Callback&& callback)
1636{
1637 BMCWEB_LOG_DEBUG << "getInventoryItemsConnections enter";
1638
1639 const std::string path = "/xyz/openbmc_project/inventory";
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001640 const std::array<std::string, 4> interfaces = {
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001641 "xyz.openbmc_project.Inventory.Item",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001642 "xyz.openbmc_project.Inventory.Item.PowerSupply",
1643 "xyz.openbmc_project.Inventory.Decorator.Asset",
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001644 "xyz.openbmc_project.State.Decorator.OperationalStatus"};
1645
1646 // Response handler for parsing output from GetSubTree
Ed Tanous002d39b2022-05-31 08:59:27 -07001647 auto respHandler =
1648 [callback{std::forward<Callback>(callback)}, sensorsAsyncResp,
1649 inventoryItems](
1650 const boost::system::error_code ec,
1651 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001652 BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler enter";
1653 if (ec)
1654 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001655 messages::internalError(sensorsAsyncResp->asyncResp->res);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001656 BMCWEB_LOG_ERROR
1657 << "getInventoryItemsConnections respHandler DBus error " << ec;
1658 return;
1659 }
1660
1661 // Make unique list of connections for desired inventory items
Nan Zhoufe04d492022-06-22 17:10:41 +00001662 std::shared_ptr<std::set<std::string>> invConnections =
1663 std::make_shared<std::set<std::string>>();
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001664
1665 // Loop through objects from GetSubTree
1666 for (const std::pair<
1667 std::string,
1668 std::vector<std::pair<std::string, std::vector<std::string>>>>&
1669 object : subtree)
1670 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001671 // Check if object path is one of the specified inventory items
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001672 const std::string& objPath = object.first;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001673 if (findInventoryItem(inventoryItems, objPath) != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001674 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001675 // Store all connections to inventory item
1676 for (const std::pair<std::string, std::vector<std::string>>&
1677 objData : object.second)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001678 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001679 const std::string& invConnection = objData.first;
1680 invConnections->insert(invConnection);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001681 }
1682 }
1683 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001684
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001685 callback(invConnections);
1686 BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler exit";
1687 };
1688
1689 // Make call to ObjectMapper to find all inventory items
1690 crow::connections::systemBus->async_method_call(
1691 std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
1692 "/xyz/openbmc_project/object_mapper",
1693 "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 0, interfaces);
1694 BMCWEB_LOG_DEBUG << "getInventoryItemsConnections exit";
1695}
1696
1697/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001698 * @brief Gets associations from sensors to inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001699 *
1700 * Looks for ObjectMapper associations from the specified sensors to related
Anthony Wilsond5005492019-07-31 16:34:17 -05001701 * inventory items. Then finds the associations from those inventory items to
1702 * their LEDs, if any.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001703 *
1704 * Finds the inventory items asynchronously. Invokes callback when information
1705 * has been obtained.
1706 *
1707 * The callback must have the following signature:
1708 * @code
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001709 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001710 * @endcode
1711 *
1712 * @param sensorsAsyncResp Pointer to object holding response data.
1713 * @param sensorNames All sensors within the current chassis.
1714 * @param objectMgrPaths Mappings from connection name to DBus object path that
1715 * implements ObjectManager.
1716 * @param callback Callback to invoke when inventory items have been obtained.
1717 */
1718template <typename Callback>
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001719static void getInventoryItemAssociations(
Ed Tanousb5a76932020-09-29 16:16:58 -07001720 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001721 const std::shared_ptr<std::set<std::string>>& sensorNames,
1722 const std::shared_ptr<std::map<std::string, std::string>>& objectMgrPaths,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001723 Callback&& callback)
1724{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001725 BMCWEB_LOG_DEBUG << "getInventoryItemAssociations enter";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001726
1727 // Response handler for GetManagedObjects
Ed Tanous02cad962022-06-30 16:50:15 -07001728 auto respHandler =
1729 [callback{std::forward<Callback>(callback)}, sensorsAsyncResp,
1730 sensorNames](const boost::system::error_code ec,
1731 const dbus::utility::ManagedObjectType& resp) {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001732 BMCWEB_LOG_DEBUG << "getInventoryItemAssociations respHandler enter";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001733 if (ec)
1734 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001735 BMCWEB_LOG_ERROR
1736 << "getInventoryItemAssociations respHandler DBus error " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +08001737 messages::internalError(sensorsAsyncResp->asyncResp->res);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001738 return;
1739 }
1740
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001741 // Create vector to hold list of inventory items
1742 std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1743 std::make_shared<std::vector<InventoryItem>>();
1744
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001745 // Loop through returned object paths
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001746 std::string sensorAssocPath;
1747 sensorAssocPath.reserve(128); // avoid memory allocations
1748 for (const auto& objDictEntry : resp)
1749 {
1750 const std::string& objPath =
1751 static_cast<const std::string&>(objDictEntry.first);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001752
1753 // If path is inventory association for one of the specified sensors
1754 for (const std::string& sensorName : *sensorNames)
1755 {
1756 sensorAssocPath = sensorName;
1757 sensorAssocPath += "/inventory";
1758 if (objPath == sensorAssocPath)
1759 {
1760 // Get Association interface for object path
Ed Tanous711ac7a2021-12-20 09:34:41 -08001761 for (const auto& [interface, values] : objDictEntry.second)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001762 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001763 if (interface == "xyz.openbmc_project.Association")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001764 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001765 for (const auto& [valueName, value] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001766 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001767 if (valueName == "endpoints")
1768 {
1769 const std::vector<std::string>* endpoints =
1770 std::get_if<std::vector<std::string>>(
1771 &value);
1772 if ((endpoints != nullptr) &&
1773 !endpoints->empty())
1774 {
1775 // Add inventory item to vector
1776 const std::string& invItemPath =
1777 endpoints->front();
1778 addInventoryItem(inventoryItems,
1779 invItemPath,
1780 sensorName);
1781 }
1782 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001783 }
1784 }
1785 }
1786 break;
1787 }
1788 }
1789 }
1790
Anthony Wilsond5005492019-07-31 16:34:17 -05001791 // Now loop through the returned object paths again, this time to
1792 // find the leds associated with the inventory items we just found
1793 std::string inventoryAssocPath;
1794 inventoryAssocPath.reserve(128); // avoid memory allocations
1795 for (const auto& objDictEntry : resp)
1796 {
1797 const std::string& objPath =
1798 static_cast<const std::string&>(objDictEntry.first);
Anthony Wilsond5005492019-07-31 16:34:17 -05001799
1800 for (InventoryItem& inventoryItem : *inventoryItems)
1801 {
1802 inventoryAssocPath = inventoryItem.objectPath;
1803 inventoryAssocPath += "/leds";
1804 if (objPath == inventoryAssocPath)
1805 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001806 for (const auto& [interface, values] : objDictEntry.second)
Anthony Wilsond5005492019-07-31 16:34:17 -05001807 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001808 if (interface == "xyz.openbmc_project.Association")
Anthony Wilsond5005492019-07-31 16:34:17 -05001809 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001810 for (const auto& [valueName, value] : values)
Anthony Wilsond5005492019-07-31 16:34:17 -05001811 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001812 if (valueName == "endpoints")
1813 {
1814 const std::vector<std::string>* endpoints =
1815 std::get_if<std::vector<std::string>>(
1816 &value);
1817 if ((endpoints != nullptr) &&
1818 !endpoints->empty())
1819 {
1820 // Add inventory item to vector
1821 // Store LED path in inventory item
1822 const std::string& ledPath =
1823 endpoints->front();
1824 inventoryItem.ledObjectPath = ledPath;
1825 }
1826 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001827 }
1828 }
1829 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001830
Anthony Wilsond5005492019-07-31 16:34:17 -05001831 break;
1832 }
1833 }
1834 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001835 callback(inventoryItems);
1836 BMCWEB_LOG_DEBUG << "getInventoryItemAssociations respHandler exit";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001837 };
1838
1839 // Find DBus object path that implements ObjectManager for ObjectMapper
1840 std::string connection = "xyz.openbmc_project.ObjectMapper";
1841 auto iter = objectMgrPaths->find(connection);
1842 const std::string& objectMgrPath =
1843 (iter != objectMgrPaths->end()) ? iter->second : "/";
1844 BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
1845 << objectMgrPath;
1846
1847 // Call GetManagedObjects on the ObjectMapper to get all associations
1848 crow::connections::systemBus->async_method_call(
1849 std::move(respHandler), connection, objectMgrPath,
1850 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1851
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001852 BMCWEB_LOG_DEBUG << "getInventoryItemAssociations exit";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001853}
1854
1855/**
Anthony Wilsond5005492019-07-31 16:34:17 -05001856 * @brief Gets D-Bus data for inventory item leds associated with sensors.
1857 *
1858 * Uses the specified connections (services) to obtain D-Bus data for inventory
1859 * item leds associated with sensors. Stores the resulting data in the
1860 * inventoryItems vector.
1861 *
1862 * This data is later used to provide sensor property values in the JSON
1863 * response.
1864 *
1865 * Finds the inventory item led data asynchronously. Invokes callback when data
1866 * has been obtained.
1867 *
1868 * The callback must have the following signature:
1869 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001870 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001871 * @endcode
1872 *
1873 * This function is called recursively, obtaining data asynchronously from one
1874 * connection in each call. This ensures the callback is not invoked until the
1875 * last asynchronous function has completed.
1876 *
1877 * @param sensorsAsyncResp Pointer to object holding response data.
1878 * @param inventoryItems D-Bus inventory items associated with sensors.
1879 * @param ledConnections Connections that provide data for the inventory leds.
1880 * @param callback Callback to invoke when inventory data has been obtained.
1881 * @param ledConnectionsIndex Current index in ledConnections. Only specified
1882 * in recursive calls to this function.
1883 */
1884template <typename Callback>
1885void getInventoryLedData(
1886 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1887 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001888 std::shared_ptr<std::map<std::string, std::string>> ledConnections,
Anthony Wilsond5005492019-07-31 16:34:17 -05001889 Callback&& callback, size_t ledConnectionsIndex = 0)
1890{
1891 BMCWEB_LOG_DEBUG << "getInventoryLedData enter";
1892
1893 // If no more connections left, call callback
1894 if (ledConnectionsIndex >= ledConnections->size())
1895 {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001896 callback();
Anthony Wilsond5005492019-07-31 16:34:17 -05001897 BMCWEB_LOG_DEBUG << "getInventoryLedData exit";
1898 return;
1899 }
1900
1901 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +00001902 auto it = ledConnections->begin();
1903 std::advance(it, ledConnectionsIndex);
Anthony Wilsond5005492019-07-31 16:34:17 -05001904 if (it != ledConnections->end())
1905 {
1906 const std::string& ledPath = (*it).first;
1907 const std::string& ledConnection = (*it).second;
1908 // Response handler for Get State property
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001909 auto respHandler =
1910 [sensorsAsyncResp, inventoryItems, ledConnections, ledPath,
Ed Tanousf94c4ec2022-01-06 12:44:41 -08001911 callback{std::forward<Callback>(callback)}, ledConnectionsIndex](
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001912 const boost::system::error_code ec, const std::string& state) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001913 BMCWEB_LOG_DEBUG << "getInventoryLedData respHandler enter";
1914 if (ec)
1915 {
1916 BMCWEB_LOG_ERROR
1917 << "getInventoryLedData respHandler DBus error " << ec;
1918 messages::internalError(sensorsAsyncResp->asyncResp->res);
1919 return;
1920 }
1921
1922 BMCWEB_LOG_DEBUG << "Led state: " << state;
1923 // Find inventory item with this LED object path
1924 InventoryItem* inventoryItem =
1925 findInventoryItemForLed(*inventoryItems, ledPath);
1926 if (inventoryItem != nullptr)
1927 {
1928 // Store LED state in InventoryItem
Ed Tanous11ba3972022-07-11 09:50:41 -07001929 if (state.ends_with("On"))
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001930 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001931 inventoryItem->ledState = LedState::ON;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001932 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001933 else if (state.ends_with("Blink"))
Anthony Wilsond5005492019-07-31 16:34:17 -05001934 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001935 inventoryItem->ledState = LedState::BLINK;
Anthony Wilsond5005492019-07-31 16:34:17 -05001936 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001937 else if (state.ends_with("Off"))
Ed Tanous002d39b2022-05-31 08:59:27 -07001938 {
1939 inventoryItem->ledState = LedState::OFF;
1940 }
1941 else
1942 {
1943 inventoryItem->ledState = LedState::UNKNOWN;
1944 }
1945 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001946
Ed Tanous002d39b2022-05-31 08:59:27 -07001947 // Recurse to get LED data from next connection
1948 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1949 ledConnections, std::move(callback),
1950 ledConnectionsIndex + 1);
Anthony Wilsond5005492019-07-31 16:34:17 -05001951
Ed Tanous002d39b2022-05-31 08:59:27 -07001952 BMCWEB_LOG_DEBUG << "getInventoryLedData respHandler exit";
1953 };
Anthony Wilsond5005492019-07-31 16:34:17 -05001954
1955 // Get the State property for the current LED
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001956 sdbusplus::asio::getProperty<std::string>(
1957 *crow::connections::systemBus, ledConnection, ledPath,
1958 "xyz.openbmc_project.Led.Physical", "State",
1959 std::move(respHandler));
Anthony Wilsond5005492019-07-31 16:34:17 -05001960 }
1961
1962 BMCWEB_LOG_DEBUG << "getInventoryLedData exit";
1963}
1964
1965/**
1966 * @brief Gets LED data for LEDs associated with given inventory items.
1967 *
1968 * Gets the D-Bus connections (services) that provide LED data for the LEDs
1969 * associated with the specified inventory items. Then gets the LED data from
1970 * each connection and stores it in the inventory item.
1971 *
1972 * This data is later used to provide sensor property values in the JSON
1973 * response.
1974 *
1975 * Finds the LED data asynchronously. Invokes callback when information has
1976 * been obtained.
1977 *
1978 * The callback must have the following signature:
1979 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001980 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001981 * @endcode
1982 *
1983 * @param sensorsAsyncResp Pointer to object holding response data.
1984 * @param inventoryItems D-Bus inventory items associated with sensors.
1985 * @param callback Callback to invoke when inventory items have been obtained.
1986 */
1987template <typename Callback>
1988void getInventoryLeds(
1989 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1990 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1991 Callback&& callback)
1992{
1993 BMCWEB_LOG_DEBUG << "getInventoryLeds enter";
1994
1995 const std::string path = "/xyz/openbmc_project";
1996 const std::array<std::string, 1> interfaces = {
1997 "xyz.openbmc_project.Led.Physical"};
1998
1999 // Response handler for parsing output from GetSubTree
Ed Tanous002d39b2022-05-31 08:59:27 -07002000 auto respHandler =
2001 [callback{std::forward<Callback>(callback)}, sensorsAsyncResp,
2002 inventoryItems](
2003 const boost::system::error_code ec,
2004 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Anthony Wilsond5005492019-07-31 16:34:17 -05002005 BMCWEB_LOG_DEBUG << "getInventoryLeds respHandler enter";
2006 if (ec)
2007 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002008 messages::internalError(sensorsAsyncResp->asyncResp->res);
Anthony Wilsond5005492019-07-31 16:34:17 -05002009 BMCWEB_LOG_ERROR << "getInventoryLeds respHandler DBus error "
2010 << ec;
2011 return;
2012 }
2013
2014 // Build map of LED object paths to connections
Nan Zhoufe04d492022-06-22 17:10:41 +00002015 std::shared_ptr<std::map<std::string, std::string>> ledConnections =
2016 std::make_shared<std::map<std::string, std::string>>();
Anthony Wilsond5005492019-07-31 16:34:17 -05002017
2018 // Loop through objects from GetSubTree
2019 for (const std::pair<
2020 std::string,
2021 std::vector<std::pair<std::string, std::vector<std::string>>>>&
2022 object : subtree)
2023 {
2024 // Check if object path is LED for one of the specified inventory
2025 // items
2026 const std::string& ledPath = object.first;
2027 if (findInventoryItemForLed(*inventoryItems, ledPath) != nullptr)
2028 {
2029 // Add mapping from ledPath to connection
2030 const std::string& connection = object.second.begin()->first;
2031 (*ledConnections)[ledPath] = connection;
2032 BMCWEB_LOG_DEBUG << "Added mapping " << ledPath << " -> "
2033 << connection;
2034 }
2035 }
2036
2037 getInventoryLedData(sensorsAsyncResp, inventoryItems, ledConnections,
2038 std::move(callback));
2039 BMCWEB_LOG_DEBUG << "getInventoryLeds respHandler exit";
2040 };
2041 // Make call to ObjectMapper to find all inventory items
2042 crow::connections::systemBus->async_method_call(
2043 std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
2044 "/xyz/openbmc_project/object_mapper",
2045 "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 0, interfaces);
2046 BMCWEB_LOG_DEBUG << "getInventoryLeds exit";
2047}
2048
2049/**
Gunnar Mills42cbe532019-08-15 15:26:54 -05002050 * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent
2051 *
2052 * Uses the specified connections (services) (currently assumes just one) to
2053 * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in
2054 * the inventoryItems vector. Only stores data in Power Supply inventoryItems.
2055 *
2056 * This data is later used to provide sensor property values in the JSON
2057 * response.
2058 *
2059 * Finds the Power Supply Attributes data asynchronously. Invokes callback
2060 * when data has been obtained.
2061 *
2062 * The callback must have the following signature:
2063 * @code
2064 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
2065 * @endcode
2066 *
2067 * @param sensorsAsyncResp Pointer to object holding response data.
2068 * @param inventoryItems D-Bus inventory items associated with sensors.
2069 * @param psAttributesConnections Connections that provide data for the Power
2070 * Supply Attributes
2071 * @param callback Callback to invoke when data has been obtained.
2072 */
2073template <typename Callback>
2074void getPowerSupplyAttributesData(
Ed Tanousb5a76932020-09-29 16:16:58 -07002075 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Gunnar Mills42cbe532019-08-15 15:26:54 -05002076 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00002077 const std::map<std::string, std::string>& psAttributesConnections,
Gunnar Mills42cbe532019-08-15 15:26:54 -05002078 Callback&& callback)
2079{
2080 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributesData enter";
2081
2082 if (psAttributesConnections.empty())
2083 {
2084 BMCWEB_LOG_DEBUG << "Can't find PowerSupplyAttributes, no connections!";
2085 callback(inventoryItems);
2086 return;
2087 }
2088
2089 // Assuming just one connection (service) for now
Nan Zhoufe04d492022-06-22 17:10:41 +00002090 auto it = psAttributesConnections.begin();
Gunnar Mills42cbe532019-08-15 15:26:54 -05002091
2092 const std::string& psAttributesPath = (*it).first;
2093 const std::string& psAttributesConnection = (*it).second;
2094
2095 // Response handler for Get DeratingFactor property
Ed Tanous002d39b2022-05-31 08:59:27 -07002096 auto respHandler =
2097 [sensorsAsyncResp, inventoryItems,
2098 callback{std::forward<Callback>(callback)}](
2099 const boost::system::error_code ec, const uint32_t value) {
Gunnar Mills42cbe532019-08-15 15:26:54 -05002100 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributesData respHandler enter";
2101 if (ec)
2102 {
2103 BMCWEB_LOG_ERROR
2104 << "getPowerSupplyAttributesData respHandler DBus error " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +08002105 messages::internalError(sensorsAsyncResp->asyncResp->res);
Gunnar Mills42cbe532019-08-15 15:26:54 -05002106 return;
2107 }
2108
Jonathan Doman1e1e5982021-06-11 09:36:17 -07002109 BMCWEB_LOG_DEBUG << "PS EfficiencyPercent value: " << value;
2110 // Store value in Power Supply Inventory Items
2111 for (InventoryItem& inventoryItem : *inventoryItems)
Gunnar Mills42cbe532019-08-15 15:26:54 -05002112 {
Ed Tanous55f79e62022-01-25 11:26:16 -08002113 if (inventoryItem.isPowerSupply)
Gunnar Mills42cbe532019-08-15 15:26:54 -05002114 {
Jonathan Doman1e1e5982021-06-11 09:36:17 -07002115 inventoryItem.powerSupplyEfficiencyPercent =
2116 static_cast<int>(value);
Gunnar Mills42cbe532019-08-15 15:26:54 -05002117 }
2118 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05002119
2120 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributesData respHandler exit";
2121 callback(inventoryItems);
2122 };
2123
2124 // Get the DeratingFactor property for the PowerSupplyAttributes
2125 // Currently only property on the interface/only one we care about
Jonathan Doman1e1e5982021-06-11 09:36:17 -07002126 sdbusplus::asio::getProperty<uint32_t>(
2127 *crow::connections::systemBus, psAttributesConnection, psAttributesPath,
2128 "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
2129 std::move(respHandler));
Gunnar Mills42cbe532019-08-15 15:26:54 -05002130
2131 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributesData exit";
2132}
2133
2134/**
2135 * @brief Gets the Power Supply Attributes such as EfficiencyPercent
2136 *
2137 * Gets the D-Bus connection (service) that provides Power Supply Attributes
2138 * data. Then gets the Power Supply Attributes data from the connection
2139 * (currently just assumes 1 connection) and stores the data in the inventory
2140 * item.
2141 *
2142 * This data is later used to provide sensor property values in the JSON
2143 * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish.
2144 *
2145 * Finds the Power Supply Attributes data asynchronously. Invokes callback
2146 * when information has been obtained.
2147 *
2148 * The callback must have the following signature:
2149 * @code
2150 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
2151 * @endcode
2152 *
2153 * @param sensorsAsyncResp Pointer to object holding response data.
2154 * @param inventoryItems D-Bus inventory items associated with sensors.
2155 * @param callback Callback to invoke when data has been obtained.
2156 */
2157template <typename Callback>
2158void getPowerSupplyAttributes(
2159 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
2160 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
2161 Callback&& callback)
2162{
2163 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes enter";
2164
2165 // Only need the power supply attributes when the Power Schema
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002166 if (sensorsAsyncResp->chassisSubNode != sensors::node::power)
Gunnar Mills42cbe532019-08-15 15:26:54 -05002167 {
2168 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes exit since not Power";
2169 callback(inventoryItems);
2170 return;
2171 }
2172
2173 const std::array<std::string, 1> interfaces = {
2174 "xyz.openbmc_project.Control.PowerSupplyAttributes"};
2175
2176 // Response handler for parsing output from GetSubTree
Ed Tanousb9d36b42022-02-26 21:42:46 -08002177 auto respHandler =
2178 [callback{std::forward<Callback>(callback)}, sensorsAsyncResp,
2179 inventoryItems](
2180 const boost::system::error_code ec,
2181 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002182 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes respHandler enter";
2183 if (ec)
2184 {
2185 messages::internalError(sensorsAsyncResp->asyncResp->res);
2186 BMCWEB_LOG_ERROR
2187 << "getPowerSupplyAttributes respHandler DBus error " << ec;
2188 return;
2189 }
2190 if (subtree.empty())
2191 {
2192 BMCWEB_LOG_DEBUG << "Can't find Power Supply Attributes!";
2193 callback(inventoryItems);
2194 return;
2195 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05002196
Ed Tanous002d39b2022-05-31 08:59:27 -07002197 // Currently we only support 1 power supply attribute, use this for
2198 // all the power supplies. Build map of object path to connection.
2199 // Assume just 1 connection and 1 path for now.
Nan Zhoufe04d492022-06-22 17:10:41 +00002200 std::map<std::string, std::string> psAttributesConnections;
Gunnar Mills42cbe532019-08-15 15:26:54 -05002201
Ed Tanous002d39b2022-05-31 08:59:27 -07002202 if (subtree[0].first.empty() || subtree[0].second.empty())
2203 {
2204 BMCWEB_LOG_DEBUG << "Power Supply Attributes mapper error!";
2205 callback(inventoryItems);
2206 return;
2207 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05002208
Ed Tanous002d39b2022-05-31 08:59:27 -07002209 const std::string& psAttributesPath = subtree[0].first;
2210 const std::string& connection = subtree[0].second.begin()->first;
Gunnar Mills42cbe532019-08-15 15:26:54 -05002211
Ed Tanous002d39b2022-05-31 08:59:27 -07002212 if (connection.empty())
2213 {
2214 BMCWEB_LOG_DEBUG << "Power Supply Attributes mapper error!";
2215 callback(inventoryItems);
2216 return;
2217 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05002218
Ed Tanous002d39b2022-05-31 08:59:27 -07002219 psAttributesConnections[psAttributesPath] = connection;
2220 BMCWEB_LOG_DEBUG << "Added mapping " << psAttributesPath << " -> "
2221 << connection;
Gunnar Mills42cbe532019-08-15 15:26:54 -05002222
Ed Tanous002d39b2022-05-31 08:59:27 -07002223 getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems,
2224 psAttributesConnections,
2225 std::move(callback));
2226 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes respHandler exit";
2227 };
Gunnar Mills42cbe532019-08-15 15:26:54 -05002228 // Make call to ObjectMapper to find the PowerSupplyAttributes service
2229 crow::connections::systemBus->async_method_call(
2230 std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
2231 "/xyz/openbmc_project/object_mapper",
2232 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
2233 "/xyz/openbmc_project", 0, interfaces);
2234 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes exit";
2235}
2236
2237/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002238 * @brief Gets inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002239 *
2240 * Finds the inventory items that are associated with the specified sensors.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002241 * Then gets D-Bus data for the inventory items, such as presence and VPD.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002242 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002243 * This data is later used to provide sensor property values in the JSON
2244 * response.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002245 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002246 * Finds the inventory items asynchronously. Invokes callback when the
2247 * inventory items have been obtained.
2248 *
2249 * The callback must have the following signature:
2250 * @code
2251 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
2252 * @endcode
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002253 *
2254 * @param sensorsAsyncResp Pointer to object holding response data.
2255 * @param sensorNames All sensors within the current chassis.
2256 * @param objectMgrPaths Mappings from connection name to DBus object path that
2257 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002258 * @param callback Callback to invoke when inventory items have been obtained.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002259 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002260template <typename Callback>
2261static void getInventoryItems(
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002262 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00002263 const std::shared_ptr<std::set<std::string>> sensorNames,
2264 std::shared_ptr<std::map<std::string, std::string>> objectMgrPaths,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002265 Callback&& callback)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002266{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002267 BMCWEB_LOG_DEBUG << "getInventoryItems enter";
2268 auto getInventoryItemAssociationsCb =
Ed Tanousf94c4ec2022-01-06 12:44:41 -08002269 [sensorsAsyncResp, objectMgrPaths,
2270 callback{std::forward<Callback>(callback)}](
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002271 std::shared_ptr<std::vector<InventoryItem>> inventoryItems) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002272 BMCWEB_LOG_DEBUG << "getInventoryItemAssociationsCb enter";
2273 auto getInventoryItemsConnectionsCb =
2274 [sensorsAsyncResp, inventoryItems, objectMgrPaths,
2275 callback{std::forward<const Callback>(callback)}](
Nan Zhoufe04d492022-06-22 17:10:41 +00002276 std::shared_ptr<std::set<std::string>> invConnections) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002277 BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb enter";
2278 auto getInventoryItemsDataCb = [sensorsAsyncResp, inventoryItems,
2279 callback{std::move(callback)}]() {
2280 BMCWEB_LOG_DEBUG << "getInventoryItemsDataCb enter";
Gunnar Mills42cbe532019-08-15 15:26:54 -05002281
Ed Tanous002d39b2022-05-31 08:59:27 -07002282 auto getInventoryLedsCb = [sensorsAsyncResp, inventoryItems,
2283 callback{std::move(callback)}]() {
2284 BMCWEB_LOG_DEBUG << "getInventoryLedsCb enter";
2285 // Find Power Supply Attributes and get the data
2286 getPowerSupplyAttributes(sensorsAsyncResp, inventoryItems,
2287 std::move(callback));
2288 BMCWEB_LOG_DEBUG << "getInventoryLedsCb exit";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002289 };
2290
Ed Tanous002d39b2022-05-31 08:59:27 -07002291 // Find led connections and get the data
2292 getInventoryLeds(sensorsAsyncResp, inventoryItems,
2293 std::move(getInventoryLedsCb));
2294 BMCWEB_LOG_DEBUG << "getInventoryItemsDataCb exit";
2295 };
2296
2297 // Get inventory item data from connections
2298 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
2299 invConnections, objectMgrPaths,
2300 std::move(getInventoryItemsDataCb));
2301 BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb exit";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002302 };
2303
Ed Tanous002d39b2022-05-31 08:59:27 -07002304 // Get connections that provide inventory item data
2305 getInventoryItemsConnections(sensorsAsyncResp, inventoryItems,
2306 std::move(getInventoryItemsConnectionsCb));
2307 BMCWEB_LOG_DEBUG << "getInventoryItemAssociationsCb exit";
2308 };
2309
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002310 // Get associations from sensors to inventory items
2311 getInventoryItemAssociations(sensorsAsyncResp, sensorNames, objectMgrPaths,
2312 std::move(getInventoryItemAssociationsCb));
2313 BMCWEB_LOG_DEBUG << "getInventoryItems exit";
2314}
2315
2316/**
2317 * @brief Returns JSON PowerSupply object for the specified inventory item.
2318 *
2319 * Searches for a JSON PowerSupply object that matches the specified inventory
2320 * item. If one is not found, a new PowerSupply object is added to the JSON
2321 * array.
2322 *
2323 * Multiple sensors are often associated with one power supply inventory item.
2324 * As a result, multiple sensor values are stored in one JSON PowerSupply
2325 * object.
2326 *
2327 * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
2328 * @param inventoryItem Inventory item for the power supply.
2329 * @param chassisId Chassis that contains the power supply.
2330 * @return JSON PowerSupply object for the specified inventory item.
2331 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002332inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002333 const InventoryItem& inventoryItem,
2334 const std::string& chassisId)
2335{
2336 // Check if matching PowerSupply object already exists in JSON array
2337 for (nlohmann::json& powerSupply : powerSupplyArray)
2338 {
2339 if (powerSupply["MemberId"] == inventoryItem.name)
2340 {
2341 return powerSupply;
2342 }
2343 }
2344
2345 // Add new PowerSupply object to JSON array
2346 powerSupplyArray.push_back({});
2347 nlohmann::json& powerSupply = powerSupplyArray.back();
2348 powerSupply["@odata.id"] =
2349 "/redfish/v1/Chassis/" + chassisId + "/Power#/PowerSupplies/";
2350 powerSupply["MemberId"] = inventoryItem.name;
2351 powerSupply["Name"] = boost::replace_all_copy(inventoryItem.name, "_", " ");
2352 powerSupply["Manufacturer"] = inventoryItem.manufacturer;
2353 powerSupply["Model"] = inventoryItem.model;
2354 powerSupply["PartNumber"] = inventoryItem.partNumber;
2355 powerSupply["SerialNumber"] = inventoryItem.serialNumber;
Anthony Wilsond5005492019-07-31 16:34:17 -05002356 setLedState(powerSupply, &inventoryItem);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002357
Gunnar Mills42cbe532019-08-15 15:26:54 -05002358 if (inventoryItem.powerSupplyEfficiencyPercent >= 0)
2359 {
2360 powerSupply["EfficiencyPercent"] =
2361 inventoryItem.powerSupplyEfficiencyPercent;
2362 }
2363
2364 powerSupply["Status"]["State"] = getState(&inventoryItem);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002365 const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
2366 powerSupply["Status"]["Health"] = health;
2367
2368 return powerSupply;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002369}
2370
2371/**
Shawn McCarneyde629b62019-03-08 10:42:51 -06002372 * @brief Gets the values of the specified sensors.
2373 *
2374 * Stores the results as JSON in the SensorsAsyncResp.
2375 *
2376 * Gets the sensor values asynchronously. Stores the results later when the
2377 * information has been obtained.
2378 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002379 * The sensorNames set contains all requested sensors for the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06002380 *
2381 * To minimize the number of DBus calls, the DBus method
2382 * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
2383 * values of all sensors provided by a connection (service).
2384 *
2385 * The connections set contains all the connections that provide sensor values.
2386 *
2387 * The objectMgrPaths map contains mappings from a connection name to the
2388 * corresponding DBus object path that implements ObjectManager.
2389 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002390 * The InventoryItem vector contains D-Bus inventory items associated with the
2391 * sensors. Inventory item data is needed for some Redfish sensor properties.
2392 *
Shawn McCarneyde629b62019-03-08 10:42:51 -06002393 * @param SensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002394 * @param sensorNames All requested sensors within the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06002395 * @param connections Connections that provide sensor values.
2396 * @param objectMgrPaths Mappings from connection name to DBus object path that
2397 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002398 * @param inventoryItems Inventory items associated with the sensors.
Shawn McCarneyde629b62019-03-08 10:42:51 -06002399 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002400inline void getSensorData(
Ed Tanous81ce6092020-12-17 16:54:55 +00002401 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00002402 const std::shared_ptr<std::set<std::string>>& sensorNames,
2403 const std::set<std::string>& connections,
2404 const std::shared_ptr<std::map<std::string, std::string>>& objectMgrPaths,
Ed Tanousb5a76932020-09-29 16:16:58 -07002405 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems)
Shawn McCarneyde629b62019-03-08 10:42:51 -06002406{
2407 BMCWEB_LOG_DEBUG << "getSensorData enter";
2408 // Get managed objects from all services exposing sensors
2409 for (const std::string& connection : connections)
2410 {
2411 // Response handler to process managed objects
Ed Tanous002d39b2022-05-31 08:59:27 -07002412 auto getManagedObjectsCb =
2413 [sensorsAsyncResp, sensorNames,
2414 inventoryItems](const boost::system::error_code ec,
Ed Tanous02cad962022-06-30 16:50:15 -07002415 const dbus::utility::ManagedObjectType& resp) {
Shawn McCarneyde629b62019-03-08 10:42:51 -06002416 BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
2417 if (ec)
2418 {
2419 BMCWEB_LOG_ERROR << "getManagedObjectsCb DBUS error: " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +08002420 messages::internalError(sensorsAsyncResp->asyncResp->res);
Shawn McCarneyde629b62019-03-08 10:42:51 -06002421 return;
2422 }
2423 // Go through all objects and update response with sensor data
2424 for (const auto& objDictEntry : resp)
2425 {
2426 const std::string& objPath =
2427 static_cast<const std::string&>(objDictEntry.first);
2428 BMCWEB_LOG_DEBUG << "getManagedObjectsCb parsing object "
2429 << objPath;
2430
Shawn McCarneyde629b62019-03-08 10:42:51 -06002431 std::vector<std::string> split;
2432 // Reserve space for
2433 // /xyz/openbmc_project/sensors/<name>/<subname>
2434 split.reserve(6);
2435 boost::algorithm::split(split, objPath, boost::is_any_of("/"));
2436 if (split.size() < 6)
2437 {
2438 BMCWEB_LOG_ERROR << "Got path that isn't long enough "
2439 << objPath;
2440 continue;
2441 }
2442 // These indexes aren't intuitive, as boost::split puts an empty
2443 // string at the beginning
2444 const std::string& sensorType = split[4];
2445 const std::string& sensorName = split[5];
2446 BMCWEB_LOG_DEBUG << "sensorName " << sensorName
2447 << " sensorType " << sensorType;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002448 if (sensorNames->find(objPath) == sensorNames->end())
Shawn McCarneyde629b62019-03-08 10:42:51 -06002449 {
Andrew Geissleraccdbb22021-11-09 15:24:45 -06002450 BMCWEB_LOG_DEBUG << sensorName << " not in sensor list ";
Shawn McCarneyde629b62019-03-08 10:42:51 -06002451 continue;
2452 }
2453
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002454 // Find inventory item (if any) associated with sensor
2455 InventoryItem* inventoryItem =
2456 findInventoryItemForSensor(inventoryItems, objPath);
2457
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002458 const std::string& sensorSchema =
Ed Tanous81ce6092020-12-17 16:54:55 +00002459 sensorsAsyncResp->chassisSubNode;
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002460
2461 nlohmann::json* sensorJson = nullptr;
2462
Nan Zhou928fefb2022-03-28 08:45:00 -07002463 if (sensorSchema == sensors::node::sensors &&
2464 !sensorsAsyncResp->efficientExpand)
Shawn McCarneyde629b62019-03-08 10:42:51 -06002465 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002466 sensorsAsyncResp->asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous81ce6092020-12-17 16:54:55 +00002467 "/redfish/v1/Chassis/" + sensorsAsyncResp->chassisId +
2468 "/" + sensorsAsyncResp->chassisSubNode + "/" +
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002469 sensorName;
zhanghch058d1b46d2021-04-01 11:18:24 +08002470 sensorJson = &(sensorsAsyncResp->asyncResp->res.jsonValue);
Shawn McCarneyde629b62019-03-08 10:42:51 -06002471 }
2472 else
2473 {
Ed Tanous271584a2019-07-09 16:24:22 -07002474 std::string fieldName;
Nan Zhou928fefb2022-03-28 08:45:00 -07002475 if (sensorsAsyncResp->efficientExpand)
2476 {
2477 fieldName = "Members";
2478 }
2479 else if (sensorType == "temperature")
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002480 {
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002481 fieldName = "Temperatures";
2482 }
2483 else if (sensorType == "fan" || sensorType == "fan_tach" ||
2484 sensorType == "fan_pwm")
2485 {
2486 fieldName = "Fans";
2487 }
2488 else if (sensorType == "voltage")
2489 {
2490 fieldName = "Voltages";
2491 }
2492 else if (sensorType == "power")
2493 {
Ed Tanous55f79e62022-01-25 11:26:16 -08002494 if (sensorName == "total_power")
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002495 {
2496 fieldName = "PowerControl";
2497 }
2498 else if ((inventoryItem != nullptr) &&
2499 (inventoryItem->isPowerSupply))
2500 {
2501 fieldName = "PowerSupplies";
2502 }
2503 else
2504 {
2505 // Other power sensors are in SensorCollection
2506 continue;
2507 }
2508 }
2509 else
2510 {
2511 BMCWEB_LOG_ERROR << "Unsure how to handle sensorType "
2512 << sensorType;
2513 continue;
2514 }
2515
2516 nlohmann::json& tempArray =
zhanghch058d1b46d2021-04-01 11:18:24 +08002517 sensorsAsyncResp->asyncResp->res.jsonValue[fieldName];
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002518 if (fieldName == "PowerControl")
2519 {
2520 if (tempArray.empty())
2521 {
2522 // Put multiple "sensors" into a single
2523 // PowerControl. Follows MemberId naming and
2524 // naming in power.hpp.
Ed Tanous14766872022-03-15 10:44:42 -07002525 nlohmann::json::object_t power;
2526 power["@odata.id"] =
2527 "/redfish/v1/Chassis/" +
2528 sensorsAsyncResp->chassisId + "/" +
2529 sensorsAsyncResp->chassisSubNode + "#/" +
2530 fieldName + "/0";
2531 tempArray.push_back(std::move(power));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002532 }
2533 sensorJson = &(tempArray.back());
2534 }
2535 else if (fieldName == "PowerSupplies")
2536 {
2537 if (inventoryItem != nullptr)
2538 {
2539 sensorJson =
2540 &(getPowerSupply(tempArray, *inventoryItem,
Ed Tanous81ce6092020-12-17 16:54:55 +00002541 sensorsAsyncResp->chassisId));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002542 }
2543 }
Nan Zhou928fefb2022-03-28 08:45:00 -07002544 else if (fieldName == "Members")
2545 {
Ed Tanous14766872022-03-15 10:44:42 -07002546 nlohmann::json::object_t member;
2547 member["@odata.id"] =
2548 "/redfish/v1/Chassis/" +
2549 sensorsAsyncResp->chassisId + "/" +
2550 sensorsAsyncResp->chassisSubNode + "/" + sensorName;
2551 tempArray.push_back(std::move(member));
Nan Zhou928fefb2022-03-28 08:45:00 -07002552 sensorJson = &(tempArray.back());
2553 }
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002554 else
2555 {
Ed Tanous14766872022-03-15 10:44:42 -07002556 nlohmann::json::object_t member;
2557 member["@odata.id"] = "/redfish/v1/Chassis/" +
2558 sensorsAsyncResp->chassisId +
2559 "/" +
2560 sensorsAsyncResp->chassisSubNode +
2561 "#/" + fieldName + "/";
2562 tempArray.push_back(std::move(member));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002563 sensorJson = &(tempArray.back());
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002564 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002565 }
Shawn McCarneyde629b62019-03-08 10:42:51 -06002566
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002567 if (sensorJson != nullptr)
2568 {
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002569 objectInterfacesToJson(
Ed Tanous81ce6092020-12-17 16:54:55 +00002570 sensorName, sensorType, sensorsAsyncResp,
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002571 objDictEntry.second, *sensorJson, inventoryItem);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002572 }
Shawn McCarneyde629b62019-03-08 10:42:51 -06002573 }
Ed Tanous81ce6092020-12-17 16:54:55 +00002574 if (sensorsAsyncResp.use_count() == 1)
James Feist8bd25cc2019-03-15 15:14:00 -07002575 {
Ed Tanous81ce6092020-12-17 16:54:55 +00002576 sortJSONResponse(sensorsAsyncResp);
Nan Zhou928fefb2022-03-28 08:45:00 -07002577 if (sensorsAsyncResp->chassisSubNode ==
2578 sensors::node::sensors &&
2579 sensorsAsyncResp->efficientExpand)
2580 {
2581 sensorsAsyncResp->asyncResp->res
2582 .jsonValue["Members@odata.count"] =
2583 sensorsAsyncResp->asyncResp->res.jsonValue["Members"]
2584 .size();
2585 }
2586 else if (sensorsAsyncResp->chassisSubNode ==
2587 sensors::node::thermal)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002588 {
Ed Tanous81ce6092020-12-17 16:54:55 +00002589 populateFanRedundancy(sensorsAsyncResp);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002590 }
James Feist8bd25cc2019-03-15 15:14:00 -07002591 }
Shawn McCarneyde629b62019-03-08 10:42:51 -06002592 BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
2593 };
2594
2595 // Find DBus object path that implements ObjectManager for the current
2596 // connection. If no mapping found, default to "/".
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002597 auto iter = objectMgrPaths->find(connection);
Shawn McCarneyde629b62019-03-08 10:42:51 -06002598 const std::string& objectMgrPath =
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002599 (iter != objectMgrPaths->end()) ? iter->second : "/";
Shawn McCarneyde629b62019-03-08 10:42:51 -06002600 BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
2601 << objectMgrPath;
2602
2603 crow::connections::systemBus->async_method_call(
2604 getManagedObjectsCb, connection, objectMgrPath,
2605 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Ed Tanous23a21a12020-07-25 04:45:05 +00002606 }
Shawn McCarneyde629b62019-03-08 10:42:51 -06002607 BMCWEB_LOG_DEBUG << "getSensorData exit";
2608}
2609
Nan Zhoufe04d492022-06-22 17:10:41 +00002610inline void
2611 processSensorList(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
2612 const std::shared_ptr<std::set<std::string>>& sensorNames)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002613{
Nan Zhoufe04d492022-06-22 17:10:41 +00002614 auto getConnectionCb = [sensorsAsyncResp, sensorNames](
2615 const std::set<std::string>& connections) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002616 BMCWEB_LOG_DEBUG << "getConnectionCb enter";
2617 auto getObjectManagerPathsCb =
Nan Zhoufe04d492022-06-22 17:10:41 +00002618 [sensorsAsyncResp, sensorNames, connections](
2619 const std::shared_ptr<std::map<std::string, std::string>>&
2620 objectMgrPaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002621 BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb enter";
2622 auto getInventoryItemsCb =
2623 [sensorsAsyncResp, sensorNames, connections, objectMgrPaths](
2624 const std::shared_ptr<std::vector<InventoryItem>>&
2625 inventoryItems) {
2626 BMCWEB_LOG_DEBUG << "getInventoryItemsCb enter";
2627 // Get sensor data and store results in JSON
2628 getSensorData(sensorsAsyncResp, sensorNames, connections,
2629 objectMgrPaths, inventoryItems);
2630 BMCWEB_LOG_DEBUG << "getInventoryItemsCb exit";
2631 };
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002632
Ed Tanous002d39b2022-05-31 08:59:27 -07002633 // Get inventory items associated with sensors
2634 getInventoryItems(sensorsAsyncResp, sensorNames, objectMgrPaths,
2635 std::move(getInventoryItemsCb));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002636
Ed Tanous002d39b2022-05-31 08:59:27 -07002637 BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb exit";
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002638 };
2639
Ed Tanous002d39b2022-05-31 08:59:27 -07002640 // Get mapping from connection names to the DBus object
2641 // paths that implement the ObjectManager interface
2642 getObjectManagerPaths(sensorsAsyncResp,
2643 std::move(getObjectManagerPathsCb));
2644 BMCWEB_LOG_DEBUG << "getConnectionCb exit";
2645 };
2646
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002647 // Get set of connections that provide sensor values
Ed Tanous81ce6092020-12-17 16:54:55 +00002648 getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002649}
2650
Shawn McCarneyde629b62019-03-08 10:42:51 -06002651/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002652 * @brief Entry point for retrieving sensors data related to requested
2653 * chassis.
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02002654 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002655 */
Ed Tanousb5a76932020-09-29 16:16:58 -07002656inline void
Ed Tanous81ce6092020-12-17 16:54:55 +00002657 getChassisData(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002658{
2659 BMCWEB_LOG_DEBUG << "getChassisData enter";
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002660 auto getChassisCb =
Ed Tanous81ce6092020-12-17 16:54:55 +00002661 [sensorsAsyncResp](
Nan Zhoufe04d492022-06-22 17:10:41 +00002662 const std::shared_ptr<std::set<std::string>>& sensorNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002663 BMCWEB_LOG_DEBUG << "getChassisCb enter";
2664 processSensorList(sensorsAsyncResp, sensorNames);
2665 BMCWEB_LOG_DEBUG << "getChassisCb exit";
2666 };
Nan Zhou928fefb2022-03-28 08:45:00 -07002667 // SensorCollection doesn't contain the Redundancy property
2668 if (sensorsAsyncResp->chassisSubNode != sensors::node::sensors)
2669 {
2670 sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
2671 nlohmann::json::array();
2672 }
Shawn McCarney26f03892019-05-03 13:20:24 -05002673 // Get set of sensors in chassis
Ed Tanous81ce6092020-12-17 16:54:55 +00002674 getChassis(sensorsAsyncResp, std::move(getChassisCb));
Ed Tanous1abe55e2018-09-05 08:30:59 -07002675 BMCWEB_LOG_DEBUG << "getChassisData exit";
Ed Tanous271584a2019-07-09 16:24:22 -07002676}
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002677
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302678/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002679 * @brief Find the requested sensorName in the list of all sensors supplied by
2680 * the chassis node
2681 *
2682 * @param sensorName The sensor name supplied in the PATCH request
2683 * @param sensorsList The list of sensors managed by the chassis node
2684 * @param sensorsModified The list of sensors that were found as a result of
2685 * repeated calls to this function
2686 */
Nan Zhoufe04d492022-06-22 17:10:41 +00002687inline bool
2688 findSensorNameUsingSensorPath(std::string_view sensorName,
Ed Tanous02cad962022-06-30 16:50:15 -07002689 const std::set<std::string>& sensorsList,
Nan Zhoufe04d492022-06-22 17:10:41 +00002690 std::set<std::string>& sensorsModified)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002691{
Nan Zhoufe04d492022-06-22 17:10:41 +00002692 for (const auto& chassisSensor : sensorsList)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002693 {
George Liu28aa8de2021-02-01 15:13:30 +08002694 sdbusplus::message::object_path path(chassisSensor);
Ed Tanousb00dcc22021-02-23 12:52:50 -08002695 std::string thisSensorName = path.filename();
George Liu28aa8de2021-02-01 15:13:30 +08002696 if (thisSensorName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002697 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002698 continue;
2699 }
2700 if (thisSensorName == sensorName)
2701 {
2702 sensorsModified.emplace(chassisSensor);
2703 return true;
2704 }
2705 }
2706 return false;
2707}
2708
2709/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302710 * @brief Entry point for overriding sensor values of given sensor
2711 *
zhanghch058d1b46d2021-04-01 11:18:24 +08002712 * @param sensorAsyncResp response object
Carol Wang4bb3dc32019-10-17 18:15:02 +08002713 * @param allCollections Collections extract from sensors' request patch info
jayaprakash Mutyala91e130a2020-03-04 22:26:38 +00002714 * @param chassisSubNode Chassis Node for which the query has to happen
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302715 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002716inline void setSensorsOverride(
Ed Tanousb5a76932020-09-29 16:16:58 -07002717 const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
Carol Wang4bb3dc32019-10-17 18:15:02 +08002718 std::unordered_map<std::string, std::vector<nlohmann::json>>&
jayaprakash Mutyala397fd612020-02-06 23:33:34 +00002719 allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302720{
jayaprakash Mutyala70d1d0a2020-01-21 23:41:36 +00002721 BMCWEB_LOG_INFO << "setSensorsOverride for subNode"
Carol Wang4bb3dc32019-10-17 18:15:02 +08002722 << sensorAsyncResp->chassisSubNode << "\n";
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302723
Ed Tanous543f4402022-01-06 13:12:53 -08002724 const char* propertyValueName = nullptr;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302725 std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302726 std::string memberId;
Ed Tanous543f4402022-01-06 13:12:53 -08002727 double value = 0.0;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302728 for (auto& collectionItems : allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302729 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302730 if (collectionItems.first == "Temperatures")
2731 {
2732 propertyValueName = "ReadingCelsius";
2733 }
2734 else if (collectionItems.first == "Fans")
2735 {
2736 propertyValueName = "Reading";
2737 }
2738 else
2739 {
2740 propertyValueName = "ReadingVolts";
2741 }
2742 for (auto& item : collectionItems.second)
2743 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002744 if (!json_util::readJson(item, sensorAsyncResp->asyncResp->res,
2745 "MemberId", memberId, propertyValueName,
2746 value))
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302747 {
2748 return;
2749 }
2750 overrideMap.emplace(memberId,
2751 std::make_pair(value, collectionItems.first));
2752 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302753 }
Carol Wang4bb3dc32019-10-17 18:15:02 +08002754
Ed Tanous002d39b2022-05-31 08:59:27 -07002755 auto getChassisSensorListCb =
2756 [sensorAsyncResp, overrideMap](
Nan Zhoufe04d492022-06-22 17:10:41 +00002757 const std::shared_ptr<std::set<std::string>>& sensorsList) {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002758 // Match sensor names in the PATCH request to those managed by the
2759 // chassis node
Nan Zhoufe04d492022-06-22 17:10:41 +00002760 const std::shared_ptr<std::set<std::string>> sensorNames =
2761 std::make_shared<std::set<std::string>>();
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302762 for (const auto& item : overrideMap)
2763 {
2764 const auto& sensor = item.first;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002765 if (!findSensorNameUsingSensorPath(sensor, *sensorsList,
2766 *sensorNames))
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302767 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302768 BMCWEB_LOG_INFO << "Unable to find memberId " << item.first;
zhanghch058d1b46d2021-04-01 11:18:24 +08002769 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302770 item.second.second, item.first);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302771 return;
2772 }
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302773 }
2774 // Get the connection to which the memberId belongs
Ed Tanous002d39b2022-05-31 08:59:27 -07002775 auto getObjectsWithConnectionCb =
Nan Zhoufe04d492022-06-22 17:10:41 +00002776 [sensorAsyncResp,
2777 overrideMap](const std::set<std::string>& /*connections*/,
2778 const std::set<std::pair<std::string, std::string>>&
2779 objectsWithConnection) {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002780 if (objectsWithConnection.size() != overrideMap.size())
2781 {
2782 BMCWEB_LOG_INFO
2783 << "Unable to find all objects with proper connection "
2784 << objectsWithConnection.size() << " requested "
2785 << overrideMap.size() << "\n";
2786 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
2787 sensorAsyncResp->chassisSubNode ==
2788 sensors::node::thermal
2789 ? "Temperatures"
2790 : "Voltages",
2791 "Count");
2792 return;
2793 }
2794 for (const auto& item : objectsWithConnection)
2795 {
2796 sdbusplus::message::object_path path(item.first);
2797 std::string sensorName = path.filename();
2798 if (sensorName.empty())
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302799 {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002800 messages::internalError(sensorAsyncResp->asyncResp->res);
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302801 return;
2802 }
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302803
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002804 const auto& iterator = overrideMap.find(sensorName);
2805 if (iterator == overrideMap.end())
2806 {
2807 BMCWEB_LOG_INFO << "Unable to find sensor object"
2808 << item.first << "\n";
2809 messages::internalError(sensorAsyncResp->asyncResp->res);
2810 return;
2811 }
2812 crow::connections::systemBus->async_method_call(
2813 [sensorAsyncResp](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002814 if (ec)
2815 {
2816 if (ec.value() ==
2817 boost::system::errc::permission_denied)
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002818 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002819 BMCWEB_LOG_WARNING
2820 << "Manufacturing mode is not Enabled...can't "
2821 "Override the sensor value. ";
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002822
Ed Tanous002d39b2022-05-31 08:59:27 -07002823 messages::insufficientPrivilege(
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002824 sensorAsyncResp->asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07002825 return;
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002826 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002827 BMCWEB_LOG_DEBUG
2828 << "setOverrideValueStatus DBUS error: " << ec;
2829 messages::internalError(
2830 sensorAsyncResp->asyncResp->res);
2831 }
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002832 },
2833 item.second, item.first, "org.freedesktop.DBus.Properties",
2834 "Set", "xyz.openbmc_project.Sensor.Value", "Value",
Ed Tanous168e20c2021-12-13 14:39:53 -08002835 dbus::utility::DbusVariantType(iterator->second.first));
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002836 }
2837 };
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302838 // Get object with connection for the given sensor name
2839 getObjectsWithConnection(sensorAsyncResp, sensorNames,
2840 std::move(getObjectsWithConnectionCb));
2841 };
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302842 // get full sensor list for the given chassisId and cross verify the sensor.
2843 getChassis(sensorAsyncResp, std::move(getChassisSensorListCb));
2844}
2845
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002846/**
2847 * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus
2848 * path of the sensor.
2849 *
2850 * Function builds valid Redfish response for sensor query of given chassis and
2851 * node. It then builds metadata about Redfish<->D-Bus correlations and provides
2852 * it to caller in a callback.
2853 *
2854 * @param chassis Chassis for which retrieval should be performed
2855 * @param node Node (group) of sensors. See sensors::node for supported values
2856 * @param mapComplete Callback to be called with retrieval result
2857 */
Krzysztof Grobelny021d32c2021-10-29 16:00:07 +02002858inline void retrieveUriToDbusMap(const std::string& chassis,
2859 const std::string& node,
2860 SensorsAsyncResp::DataCompleteCb&& mapComplete)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002861{
Ed Tanous02da7c52022-02-27 00:09:02 -08002862 decltype(sensors::paths)::const_iterator pathIt =
2863 std::find_if(sensors::paths.cbegin(), sensors::paths.cend(),
2864 [&node](auto&& val) { return val.first == node; });
2865 if (pathIt == sensors::paths.cend())
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002866 {
2867 BMCWEB_LOG_ERROR << "Wrong node provided : " << node;
2868 mapComplete(boost::beast::http::status::bad_request, {});
2869 return;
2870 }
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002871
Nan Zhou72374eb2022-01-27 17:06:51 -08002872 auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
Nan Zhoufe04d492022-06-22 17:10:41 +00002873 auto callback = [asyncResp, mapCompleteCb{std::move(mapComplete)}](
2874 const boost::beast::http::status status,
2875 const std::map<std::string, std::string>& uriToDbus) {
2876 mapCompleteCb(status, uriToDbus);
2877 };
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002878
2879 auto resp = std::make_shared<SensorsAsyncResp>(
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002880 asyncResp, chassis, pathIt->second, node, std::move(callback));
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002881 getChassisData(resp);
2882}
2883
Nan Zhoubacb2162022-04-06 11:28:32 -07002884namespace sensors
2885{
Nan Zhou928fefb2022-03-28 08:45:00 -07002886
Nan Zhoubacb2162022-04-06 11:28:32 -07002887inline void getChassisCallback(
2888 const std::shared_ptr<SensorsAsyncResp>& asyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00002889 const std::shared_ptr<std::set<std::string>>& sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002890{
2891 BMCWEB_LOG_DEBUG << "getChassisCallback enter";
2892
2893 nlohmann::json& entriesArray =
2894 asyncResp->asyncResp->res.jsonValue["Members"];
Nan Zhoufe04d492022-06-22 17:10:41 +00002895 for (const auto& sensor : *sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002896 {
2897 BMCWEB_LOG_DEBUG << "Adding sensor: " << sensor;
2898
2899 sdbusplus::message::object_path path(sensor);
2900 std::string sensorName = path.filename();
2901 if (sensorName.empty())
2902 {
2903 BMCWEB_LOG_ERROR << "Invalid sensor path: " << sensor;
2904 messages::internalError(asyncResp->asyncResp->res);
2905 return;
2906 }
Ed Tanous14766872022-03-15 10:44:42 -07002907 nlohmann::json::object_t member;
2908 member["@odata.id"] = "/redfish/v1/Chassis/" + asyncResp->chassisId +
2909 "/" + asyncResp->chassisSubNode + "/" +
2910 sensorName;
2911 entriesArray.push_back(std::move(member));
Nan Zhoubacb2162022-04-06 11:28:32 -07002912 }
2913
2914 asyncResp->asyncResp->res.jsonValue["Members@odata.count"] =
2915 entriesArray.size();
2916 BMCWEB_LOG_DEBUG << "getChassisCallback exit";
2917}
Nan Zhoue6bd8462022-06-01 04:35:35 +00002918
Nan Zhoude167a62022-06-01 04:47:45 +00002919inline void
2920 handleSensorCollectionGet(App& app, const crow::Request& req,
2921 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2922 const std::string& chassisId)
2923{
2924 query_param::QueryCapabilities capabilities = {
2925 .canDelegateExpandLevel = 1,
2926 };
2927 query_param::Query delegatedQuery;
Carson Labrado3ba00072022-06-06 19:40:56 +00002928 if (!redfish::setUpRedfishRouteWithDelegation(app, req, aResp,
Nan Zhoude167a62022-06-01 04:47:45 +00002929 delegatedQuery, capabilities))
2930 {
2931 return;
2932 }
2933
2934 if (delegatedQuery.expandType != query_param::ExpandType::None)
2935 {
2936 // we perform efficient expand.
2937 auto asyncResp = std::make_shared<SensorsAsyncResp>(
2938 aResp, chassisId, sensors::dbus::sensorPaths,
2939 sensors::node::sensors,
2940 /*efficientExpand=*/true);
2941 getChassisData(asyncResp);
2942
2943 BMCWEB_LOG_DEBUG
2944 << "SensorCollection doGet exit via efficient expand handler";
2945 return;
Ed Tanous0bad3202022-06-02 13:53:59 -07002946 }
Nan Zhoude167a62022-06-01 04:47:45 +00002947
2948 // if there's no efficient expand available, we use the default
2949 // Query Parameters route
2950 auto asyncResp = std::make_shared<SensorsAsyncResp>(
2951 aResp, chassisId, sensors::dbus::sensorPaths, sensors::node::sensors);
2952
2953 // We get all sensors as hyperlinkes in the chassis (this
2954 // implies we reply on the default query parameters handler)
2955 getChassis(asyncResp,
2956 std::bind_front(sensors::getChassisCallback, asyncResp));
2957 BMCWEB_LOG_DEBUG << "SensorCollection doGet exit";
2958}
2959
Nan Zhoue6bd8462022-06-01 04:35:35 +00002960inline void handleSensorGet(App& app, const crow::Request& req,
2961 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2962 const std::string& chassisId,
2963 const std::string& sensorName)
2964{
Carson Labrado3ba00072022-06-06 19:40:56 +00002965 if (!redfish::setUpRedfishRoute(app, req, aResp))
Nan Zhoue6bd8462022-06-01 04:35:35 +00002966 {
2967 return;
2968 }
2969 BMCWEB_LOG_DEBUG << "Sensor doGet enter";
2970 std::shared_ptr<SensorsAsyncResp> asyncResp =
2971 std::make_shared<SensorsAsyncResp>(aResp, chassisId,
2972 std::span<std::string_view>(),
2973 sensors::node::sensors);
2974
2975 const std::array<const char*, 1> interfaces = {
2976 "xyz.openbmc_project.Sensor.Value"};
2977
2978 // Get a list of all of the sensors that implement Sensor.Value
2979 // and get the path and service name associated with the sensor
2980 crow::connections::systemBus->async_method_call(
2981 [asyncResp,
2982 sensorName](const boost::system::error_code ec,
2983 const ::dbus::utility::MapperGetSubTreeResponse& subtree) {
2984 BMCWEB_LOG_DEBUG << "respHandler1 enter";
2985 if (ec)
2986 {
2987 messages::internalError(asyncResp->asyncResp->res);
2988 BMCWEB_LOG_ERROR << "Sensor getSensorPaths resp_handler: "
2989 << "Dbus error " << ec;
2990 return;
2991 }
2992
2993 ::dbus::utility::MapperGetSubTreeResponse::const_iterator it =
2994 std::find_if(
2995 subtree.begin(), subtree.end(),
2996 [sensorName](
2997 const std::pair<
2998 std::string,
2999 std::vector<std::pair<
3000 std::string, std::vector<std::string>>>>& object) {
3001 sdbusplus::message::object_path path(object.first);
3002 std::string name = path.filename();
3003 if (name.empty())
3004 {
3005 BMCWEB_LOG_ERROR << "Invalid sensor path: " << object.first;
3006 return false;
3007 }
3008
3009 return name == sensorName;
3010 });
3011
3012 if (it == subtree.end())
3013 {
3014 BMCWEB_LOG_ERROR << "Could not find path for sensor: "
3015 << sensorName;
3016 messages::resourceNotFound(asyncResp->asyncResp->res, "Sensor",
3017 sensorName);
3018 return;
3019 }
3020 std::string_view sensorPath = (*it).first;
3021 BMCWEB_LOG_DEBUG << "Found sensor path for sensor '" << sensorName
3022 << "': " << sensorPath;
3023
Nan Zhoufe04d492022-06-22 17:10:41 +00003024 const std::shared_ptr<std::set<std::string>> sensorList =
3025 std::make_shared<std::set<std::string>>();
Nan Zhoue6bd8462022-06-01 04:35:35 +00003026
3027 sensorList->emplace(sensorPath);
3028 processSensorList(asyncResp, sensorList);
3029 BMCWEB_LOG_DEBUG << "respHandler1 exit";
3030 },
3031 "xyz.openbmc_project.ObjectMapper",
3032 "/xyz/openbmc_project/object_mapper",
3033 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3034 "/xyz/openbmc_project/sensors", 2, interfaces);
3035}
3036
Nan Zhoubacb2162022-04-06 11:28:32 -07003037} // namespace sensors
3038
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003039inline void requestRoutesSensorCollection(App& app)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05003040{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003041 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
Ed Tanoused398212021-06-09 17:05:54 -07003042 .privileges(redfish::privileges::getSensorCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07003043 .methods(boost::beast::http::verb::get)(
Nan Zhoude167a62022-06-01 04:47:45 +00003044 std::bind_front(sensors::handleSensorCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003045}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05003046
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003047inline void requestRoutesSensor(App& app)
3048{
3049 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003050 .privileges(redfish::privileges::getSensor)
Ed Tanous002d39b2022-05-31 08:59:27 -07003051 .methods(boost::beast::http::verb::get)(
Nan Zhoue6bd8462022-06-01 04:35:35 +00003052 std::bind_front(sensors::handleSensorGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003053}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05003054
Ed Tanous1abe55e2018-09-05 08:30:59 -07003055} // namespace redfish