blob: 8be861ba653c4acdeaa3c60c6636a328fb236309 [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
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080018#include "app.hpp"
19#include "dbus_singleton.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080020#include "dbus_utility.hpp"
Matt Simmeringaaf08ac2023-10-04 08:41:01 -070021#include "generated/enums/resource.hpp"
Ed Tanous0ec8b832022-03-14 14:56:47 -070022#include "generated/enums/sensor.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080023#include "query.hpp"
24#include "registries/privilege_registry.hpp"
Ed Tanous50ebd4a2023-01-19 19:03:17 -080025#include "str_utility.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080026#include "utils/dbus_utils.hpp"
27#include "utils/json_utils.hpp"
28#include "utils/query_param.hpp"
Ed Tanous0ec8b832022-03-14 14:56:47 -070029
George Liue99073f2022-12-09 11:06:16 +080030#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070031#include <boost/url/format.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070032#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +020033#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050034
George Liu7a1dbc42022-12-07 16:03:22 +080035#include <array>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050036#include <cmath>
Nan Zhoufe04d492022-06-22 17:10:41 +000037#include <iterator>
Ed Tanous283860f2022-08-29 14:08:50 -070038#include <limits>
Nan Zhoufe04d492022-06-22 17:10:41 +000039#include <map>
Ed Tanous3544d2a2023-08-06 18:12:20 -070040#include <ranges>
Nan Zhoufe04d492022-06-22 17:10:41 +000041#include <set>
Ed Tanous18f8f602023-07-18 10:07:23 -070042#include <string>
George Liu7a1dbc42022-12-07 16:03:22 +080043#include <string_view>
Ed Tanousb5a76932020-09-29 16:16:58 -070044#include <utility>
Ed Tanousabf2add2019-01-22 16:40:12 -080045#include <variant>
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010046
Ed Tanous1abe55e2018-09-05 08:30:59 -070047namespace redfish
48{
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010049
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020050namespace sensors
51{
52namespace node
53{
54static constexpr std::string_view power = "Power";
55static constexpr std::string_view sensors = "Sensors";
56static constexpr std::string_view thermal = "Thermal";
57} // namespace node
58
Ed Tanous02da7c52022-02-27 00:09:02 -080059// clang-format off
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020060namespace dbus
61{
Ed Tanouscf9e4172022-12-21 09:30:16 -080062constexpr auto powerPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080063 "/xyz/openbmc_project/sensors/voltage",
64 "/xyz/openbmc_project/sensors/power"
65});
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000066
Ed Tanous25b54db2024-04-17 15:40:31 -070067constexpr auto getSensorPaths(){
68 if constexpr(BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM){
69 return std::to_array<std::string_view>({
70 "/xyz/openbmc_project/sensors/power",
71 "/xyz/openbmc_project/sensors/current",
72 "/xyz/openbmc_project/sensors/airflow",
73 "/xyz/openbmc_project/sensors/humidity",
74 "/xyz/openbmc_project/sensors/voltage",
75 "/xyz/openbmc_project/sensors/fan_tach",
76 "/xyz/openbmc_project/sensors/temperature",
77 "/xyz/openbmc_project/sensors/fan_pwm",
78 "/xyz/openbmc_project/sensors/altitude",
79 "/xyz/openbmc_project/sensors/energy",
80 "/xyz/openbmc_project/sensors/utilization"});
81 } else {
82 return std::to_array<std::string_view>({"/xyz/openbmc_project/sensors/power",
83 "/xyz/openbmc_project/sensors/current",
84 "/xyz/openbmc_project/sensors/airflow",
85 "/xyz/openbmc_project/sensors/humidity",
86 "/xyz/openbmc_project/sensors/utilization"});
87}
88}
89
90constexpr auto sensorPaths = getSensorPaths();
Ed Tanous02da7c52022-02-27 00:09:02 -080091
Ed Tanouscf9e4172022-12-21 09:30:16 -080092constexpr auto thermalPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080093 "/xyz/openbmc_project/sensors/fan_tach",
94 "/xyz/openbmc_project/sensors/temperature",
95 "/xyz/openbmc_project/sensors/fan_pwm"
96});
97
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000098} // namespace dbus
Ed Tanous02da7c52022-02-27 00:09:02 -080099// clang-format on
100
Ed Tanouscf9e4172022-12-21 09:30:16 -0800101using sensorPair =
102 std::pair<std::string_view, std::span<const std::string_view>>;
Ed Tanous02da7c52022-02-27 00:09:02 -0800103static constexpr std::array<sensorPair, 3> paths = {
Ed Tanouscf9e4172022-12-21 09:30:16 -0800104 {{node::power, dbus::powerPaths},
105 {node::sensors, dbus::sensorPaths},
106 {node::thermal, dbus::thermalPaths}}};
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000107
Ed Tanous0ec8b832022-03-14 14:56:47 -0700108inline sensor::ReadingType toReadingType(std::string_view sensorType)
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000109{
110 if (sensorType == "voltage")
111 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700112 return sensor::ReadingType::Voltage;
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000113 }
114 if (sensorType == "power")
115 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700116 return sensor::ReadingType::Power;
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000117 }
118 if (sensorType == "current")
119 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700120 return sensor::ReadingType::Current;
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000121 }
122 if (sensorType == "fan_tach")
123 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700124 return sensor::ReadingType::Rotational;
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000125 }
126 if (sensorType == "temperature")
127 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700128 return sensor::ReadingType::Temperature;
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000129 }
130 if (sensorType == "fan_pwm" || sensorType == "utilization")
131 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700132 return sensor::ReadingType::Percent;
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000133 }
Gunnar Mills5deabed2022-04-20 13:43:45 -0600134 if (sensorType == "humidity")
135 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700136 return sensor::ReadingType::Humidity;
Gunnar Mills5deabed2022-04-20 13:43:45 -0600137 }
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000138 if (sensorType == "altitude")
139 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700140 return sensor::ReadingType::Altitude;
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000141 }
142 if (sensorType == "airflow")
143 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700144 return sensor::ReadingType::AirFlow;
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000145 }
146 if (sensorType == "energy")
147 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700148 return sensor::ReadingType::EnergyJoules;
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000149 }
Ed Tanous0ec8b832022-03-14 14:56:47 -0700150 return sensor::ReadingType::Invalid;
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000151}
152
Ed Tanous1d7c0052022-08-09 12:32:26 -0700153inline std::string_view toReadingUnits(std::string_view sensorType)
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000154{
155 if (sensorType == "voltage")
156 {
157 return "V";
158 }
159 if (sensorType == "power")
160 {
161 return "W";
162 }
163 if (sensorType == "current")
164 {
165 return "A";
166 }
167 if (sensorType == "fan_tach")
168 {
169 return "RPM";
170 }
171 if (sensorType == "temperature")
172 {
173 return "Cel";
174 }
Gunnar Mills5deabed2022-04-20 13:43:45 -0600175 if (sensorType == "fan_pwm" || sensorType == "utilization" ||
176 sensorType == "humidity")
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000177 {
178 return "%";
179 }
180 if (sensorType == "altitude")
181 {
182 return "m";
183 }
184 if (sensorType == "airflow")
185 {
186 return "cft_i/min";
187 }
188 if (sensorType == "energy")
189 {
190 return "J";
191 }
192 return "";
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200193}
194} // namespace sensors
195
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100196/**
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200197 * SensorsAsyncResp
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100198 * Gathers data needed for response processing after async calls are done
199 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700200class SensorsAsyncResp
201{
202 public:
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200203 using DataCompleteCb = std::function<void(
204 const boost::beast::http::status status,
Nan Zhoufe04d492022-06-22 17:10:41 +0000205 const std::map<std::string, std::string>& uriToDbus)>;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200206
207 struct SensorData
208 {
209 const std::string name;
210 std::string uri;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200211 const std::string dbusPath;
212 };
213
Ed Tanous8a592812022-06-04 09:06:59 -0700214 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800215 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800216 std::span<const std::string_view> typesIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800217 std::string_view subNode) :
Ed Tanous8a592812022-06-04 09:06:59 -0700218 asyncResp(asyncRespIn),
Nan Zhou928fefb2022-03-28 08:45:00 -0700219 chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode),
220 efficientExpand(false)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500221 {}
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200222
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200223 // Store extra data about sensor mapping and return it in callback
Ed Tanous8a592812022-06-04 09:06:59 -0700224 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800225 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800226 std::span<const std::string_view> typesIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800227 std::string_view subNode,
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200228 DataCompleteCb&& creationComplete) :
Ed Tanous8a592812022-06-04 09:06:59 -0700229 asyncResp(asyncRespIn),
Nan Zhou928fefb2022-03-28 08:45:00 -0700230 chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode),
231 efficientExpand(false), metadata{std::vector<SensorData>()},
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200232 dataComplete{std::move(creationComplete)}
233 {}
234
Nan Zhou928fefb2022-03-28 08:45:00 -0700235 // sensor collections expand
Ed Tanous8a592812022-06-04 09:06:59 -0700236 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
Nan Zhou928fefb2022-03-28 08:45:00 -0700237 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800238 std::span<const std::string_view> typesIn,
Ed Tanous8a592812022-06-04 09:06:59 -0700239 const std::string_view& subNode, bool efficientExpandIn) :
240 asyncResp(asyncRespIn),
Nan Zhou928fefb2022-03-28 08:45:00 -0700241 chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode),
Ed Tanous8a592812022-06-04 09:06:59 -0700242 efficientExpand(efficientExpandIn)
Nan Zhou928fefb2022-03-28 08:45:00 -0700243 {}
244
Ed Tanous1abe55e2018-09-05 08:30:59 -0700245 ~SensorsAsyncResp()
246 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800247 if (asyncResp->res.result() ==
248 boost::beast::http::status::internal_server_error)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700249 {
250 // Reset the json object to clear out any data that made it in
251 // before the error happened todo(ed) handle error condition with
252 // proper code
zhanghch058d1b46d2021-04-01 11:18:24 +0800253 asyncResp->res.jsonValue = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700254 }
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200255
256 if (dataComplete && metadata)
257 {
Nan Zhoufe04d492022-06-22 17:10:41 +0000258 std::map<std::string, std::string> map;
zhanghch058d1b46d2021-04-01 11:18:24 +0800259 if (asyncResp->res.result() == boost::beast::http::status::ok)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200260 {
261 for (auto& sensor : *metadata)
262 {
Ed Tanousc1d019a2022-08-06 09:36:06 -0700263 map.emplace(sensor.uri, sensor.dbusPath);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200264 }
265 }
zhanghch058d1b46d2021-04-01 11:18:24 +0800266 dataComplete(asyncResp->res.result(), map);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200267 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700268 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100269
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800270 SensorsAsyncResp(const SensorsAsyncResp&) = delete;
271 SensorsAsyncResp(SensorsAsyncResp&&) = delete;
272 SensorsAsyncResp& operator=(const SensorsAsyncResp&) = delete;
273 SensorsAsyncResp& operator=(SensorsAsyncResp&&) = delete;
274
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200275 void addMetadata(const nlohmann::json& sensorObject,
Ed Tanousc1d019a2022-08-06 09:36:06 -0700276 const std::string& dbusPath)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200277 {
278 if (metadata)
279 {
Ed Tanousc1d019a2022-08-06 09:36:06 -0700280 metadata->emplace_back(SensorData{
281 sensorObject["Name"], sensorObject["@odata.id"], dbusPath});
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200282 }
283 }
284
285 void updateUri(const std::string& name, const std::string& uri)
286 {
287 if (metadata)
288 {
289 for (auto& sensor : *metadata)
290 {
291 if (sensor.name == name)
292 {
293 sensor.uri = uri;
294 }
295 }
296 }
297 }
298
zhanghch058d1b46d2021-04-01 11:18:24 +0800299 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200300 const std::string chassisId;
Ed Tanouscf9e4172022-12-21 09:30:16 -0800301 const std::span<const std::string_view> types;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200302 const std::string chassisSubNode;
Nan Zhou928fefb2022-03-28 08:45:00 -0700303 const bool efficientExpand;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200304
305 private:
306 std::optional<std::vector<SensorData>> metadata;
307 DataCompleteCb dataComplete;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100308};
309
310/**
Anthony Wilsond5005492019-07-31 16:34:17 -0500311 * Possible states for physical inventory leds
312 */
313enum class LedState
314{
315 OFF,
316 ON,
317 BLINK,
318 UNKNOWN
319};
320
321/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500322 * D-Bus inventory item associated with one or more sensors.
323 */
324class InventoryItem
325{
326 public:
Ed Tanous4e23a442022-06-06 09:57:26 -0700327 explicit InventoryItem(const std::string& objPath) : objectPath(objPath)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500328 {
329 // Set inventory item name to last node of object path
George Liu28aa8de2021-02-01 15:13:30 +0800330 sdbusplus::message::object_path path(objectPath);
331 name = path.filename();
332 if (name.empty())
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500333 {
Ed Tanous62598e32023-07-17 17:06:25 -0700334 BMCWEB_LOG_ERROR("Failed to find '/' in {}", objectPath);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500335 }
336 }
337
338 std::string objectPath;
339 std::string name;
Ed Tanouse05aec52022-01-25 10:28:56 -0800340 bool isPresent = true;
341 bool isFunctional = true;
342 bool isPowerSupply = false;
343 int powerSupplyEfficiencyPercent = -1;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500344 std::string manufacturer;
345 std::string model;
346 std::string partNumber;
347 std::string serialNumber;
348 std::set<std::string> sensors;
Anthony Wilsond5005492019-07-31 16:34:17 -0500349 std::string ledObjectPath;
Ed Tanouse05aec52022-01-25 10:28:56 -0800350 LedState ledState = LedState::UNKNOWN;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500351};
352
353/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530354 * @brief Get objects with connection necessary for sensors
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200355 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100356 * @param sensorNames Sensors retrieved from chassis
357 * @param callback Callback for processing gathered connections
358 */
359template <typename Callback>
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530360void getObjectsWithConnection(
Ed Tanous81ce6092020-12-17 16:54:55 +0000361 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +0000362 const std::shared_ptr<std::set<std::string>>& sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530363 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700364{
Ed Tanous62598e32023-07-17 17:06:25 -0700365 BMCWEB_LOG_DEBUG("getObjectsWithConnection enter");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700366 const std::string path = "/xyz/openbmc_project/sensors";
George Liue99073f2022-12-09 11:06:16 +0800367 constexpr std::array<std::string_view, 1> interfaces = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700368 "xyz.openbmc_project.Sensor.Value"};
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100369
George Liue99073f2022-12-09 11:06:16 +0800370 // Make call to ObjectMapper to find all sensors objects
371 dbus::utility::getSubTree(
372 path, 2, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700373 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
George Liue99073f2022-12-09 11:06:16 +0800374 sensorNames](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700375 const dbus::utility::MapperGetSubTreeResponse& subtree) {
George Liue99073f2022-12-09 11:06:16 +0800376 // Response handler for parsing objects subtree
Ed Tanous62598e32023-07-17 17:06:25 -0700377 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler enter");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700378 if (ec)
379 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800380 messages::internalError(sensorsAsyncResp->asyncResp->res);
Ed Tanous62598e32023-07-17 17:06:25 -0700381 BMCWEB_LOG_ERROR(
382 "getObjectsWithConnection resp_handler: Dbus error {}", ec);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700383 return;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100384 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100385
Ed Tanous62598e32023-07-17 17:06:25 -0700386 BMCWEB_LOG_DEBUG("Found {} subtrees", subtree.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700387
388 // Make unique list of connections only for requested sensor types and
389 // found in the chassis
Nan Zhoufe04d492022-06-22 17:10:41 +0000390 std::set<std::string> connections;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530391 std::set<std::pair<std::string, std::string>> objectsWithConnection;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700392
Ed Tanous62598e32023-07-17 17:06:25 -0700393 BMCWEB_LOG_DEBUG("sensorNames list count: {}", sensorNames->size());
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700394 for (const std::string& tsensor : *sensorNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700395 {
Ed Tanous62598e32023-07-17 17:06:25 -0700396 BMCWEB_LOG_DEBUG("Sensor to find: {}", tsensor);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700397 }
398
399 for (const std::pair<
400 std::string,
401 std::vector<std::pair<std::string, std::vector<std::string>>>>&
402 object : subtree)
403 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700404 if (sensorNames->find(object.first) != sensorNames->end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700405 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700406 for (const std::pair<std::string, std::vector<std::string>>&
407 objData : object.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700408 {
Ed Tanous62598e32023-07-17 17:06:25 -0700409 BMCWEB_LOG_DEBUG("Adding connection: {}", objData.first);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700410 connections.insert(objData.first);
411 objectsWithConnection.insert(
412 std::make_pair(object.first, objData.first));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700413 }
414 }
415 }
Ed Tanous62598e32023-07-17 17:06:25 -0700416 BMCWEB_LOG_DEBUG("Found {} connections", connections.size());
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530417 callback(std::move(connections), std::move(objectsWithConnection));
Ed Tanous62598e32023-07-17 17:06:25 -0700418 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler exit");
Patrick Williams5a39f772023-10-20 11:20:21 -0500419 });
Ed Tanous62598e32023-07-17 17:06:25 -0700420 BMCWEB_LOG_DEBUG("getObjectsWithConnection exit");
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530421}
422
423/**
424 * @brief Create connections necessary for sensors
425 * @param SensorsAsyncResp Pointer to object holding response data
426 * @param sensorNames Sensors retrieved from chassis
427 * @param callback Callback for processing gathered connections
428 */
429template <typename Callback>
Nan Zhoufe04d492022-06-22 17:10:41 +0000430void getConnections(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
431 const std::shared_ptr<std::set<std::string>> sensorNames,
432 Callback&& callback)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530433{
434 auto objectsWithConnectionCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -0700435 [callback = std::forward<Callback>(callback)](
436 const std::set<std::string>& connections,
437 const std::set<std::pair<std::string, std::string>>&
438 /*objectsWithConnection*/) { callback(connections); };
Ed Tanous81ce6092020-12-17 16:54:55 +0000439 getObjectsWithConnection(sensorsAsyncResp, sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530440 std::move(objectsWithConnectionCb));
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100441}
442
443/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700444 * @brief Shrinks the list of sensors for processing
445 * @param SensorsAysncResp The class holding the Redfish response
446 * @param allSensors A list of all the sensors associated to the
447 * chassis element (i.e. baseboard, front panel, etc...)
448 * @param activeSensors A list that is a reduction of the incoming
449 * allSensors list. Eliminate Thermal sensors when a Power request is
450 * made, and eliminate Power sensors when a Thermal request is made.
451 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000452inline void reduceSensorList(
Ed Tanous7f1cc262022-08-09 13:33:57 -0700453 crow::Response& res, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800454 std::span<const std::string_view> sensorTypes,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700455 const std::vector<std::string>* allSensors,
Nan Zhoufe04d492022-06-22 17:10:41 +0000456 const std::shared_ptr<std::set<std::string>>& activeSensors)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700457{
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700458 if ((allSensors == nullptr) || (activeSensors == nullptr))
459 {
Ed Tanous7f1cc262022-08-09 13:33:57 -0700460 messages::resourceNotFound(res, chassisSubNode,
461 chassisSubNode == sensors::node::thermal
462 ? "Temperatures"
463 : "Voltages");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700464
465 return;
466 }
467 if (allSensors->empty())
468 {
469 // Nothing to do, the activeSensors object is also empty
470 return;
471 }
472
Ed Tanous7f1cc262022-08-09 13:33:57 -0700473 for (std::string_view type : sensorTypes)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700474 {
475 for (const std::string& sensor : *allSensors)
476 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700477 if (sensor.starts_with(type))
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700478 {
479 activeSensors->emplace(sensor);
480 }
481 }
482 }
483}
484
Ed Tanous7f1cc262022-08-09 13:33:57 -0700485/*
486 *Populates the top level collection for a given subnode. Populates
487 *SensorCollection, Power, or Thermal schemas.
488 *
489 * */
490inline void populateChassisNode(nlohmann::json& jsonValue,
491 std::string_view chassisSubNode)
492{
493 if (chassisSubNode == sensors::node::power)
494 {
495 jsonValue["@odata.type"] = "#Power.v1_5_2.Power";
496 }
497 else if (chassisSubNode == sensors::node::thermal)
498 {
499 jsonValue["@odata.type"] = "#Thermal.v1_4_0.Thermal";
500 jsonValue["Fans"] = nlohmann::json::array();
501 jsonValue["Temperatures"] = nlohmann::json::array();
502 }
503 else if (chassisSubNode == sensors::node::sensors)
504 {
505 jsonValue["@odata.type"] = "#SensorCollection.SensorCollection";
506 jsonValue["Description"] = "Collection of Sensors for this Chassis";
507 jsonValue["Members"] = nlohmann::json::array();
508 jsonValue["Members@odata.count"] = 0;
509 }
510
511 if (chassisSubNode != sensors::node::sensors)
512 {
513 jsonValue["Id"] = chassisSubNode;
514 }
515 jsonValue["Name"] = chassisSubNode;
516}
517
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700518/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100519 * @brief Retrieves requested chassis sensors and redundancy data from DBus .
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200520 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100521 * @param callback Callback for next step in gathered sensor processing
522 */
523template <typename Callback>
Ed Tanous7f1cc262022-08-09 13:33:57 -0700524void getChassis(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
525 std::string_view chassisId, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800526 std::span<const std::string_view> sensorTypes,
527 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700528{
Ed Tanous62598e32023-07-17 17:06:25 -0700529 BMCWEB_LOG_DEBUG("getChassis enter");
George Liu7a1dbc42022-12-07 16:03:22 +0800530 constexpr std::array<std::string_view, 2> interfaces = {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700531 "xyz.openbmc_project.Inventory.Item.Board",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500532 "xyz.openbmc_project.Inventory.Item.Chassis"};
George Liu7a1dbc42022-12-07 16:03:22 +0800533
534 // Get the Chassis Collection
535 dbus::utility::getSubTreePaths(
536 "/xyz/openbmc_project/inventory", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700537 [callback = std::forward<Callback>(callback), asyncResp,
Ed Tanous7f1cc262022-08-09 13:33:57 -0700538 chassisIdStr{std::string(chassisId)},
539 chassisSubNode{std::string(chassisSubNode)}, sensorTypes](
George Liu7a1dbc42022-12-07 16:03:22 +0800540 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700541 const dbus::utility::MapperGetSubTreePathsResponse& chassisPaths) {
Ed Tanous62598e32023-07-17 17:06:25 -0700542 BMCWEB_LOG_DEBUG("getChassis respHandler enter");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700543 if (ec)
544 {
Ed Tanous62598e32023-07-17 17:06:25 -0700545 BMCWEB_LOG_ERROR("getChassis respHandler DBUS error: {}", ec);
Ed Tanous7f1cc262022-08-09 13:33:57 -0700546 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700547 return;
548 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700549 const std::string* chassisPath = nullptr;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700550 for (const std::string& chassis : chassisPaths)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700551 {
George Liu28aa8de2021-02-01 15:13:30 +0800552 sdbusplus::message::object_path path(chassis);
Ed Tanousf8fe53e2022-06-30 15:55:45 -0700553 std::string chassisName = path.filename();
George Liu28aa8de2021-02-01 15:13:30 +0800554 if (chassisName.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700555 {
Ed Tanous62598e32023-07-17 17:06:25 -0700556 BMCWEB_LOG_ERROR("Failed to find '/' in {}", chassis);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700557 continue;
558 }
Ed Tanous7f1cc262022-08-09 13:33:57 -0700559 if (chassisName == chassisIdStr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700560 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700561 chassisPath = &chassis;
562 break;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700563 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700564 }
565 if (chassisPath == nullptr)
566 {
Ed Tanous7f1cc262022-08-09 13:33:57 -0700567 messages::resourceNotFound(asyncResp->res, "Chassis", chassisIdStr);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700568 return;
569 }
Ed Tanous7f1cc262022-08-09 13:33:57 -0700570 populateChassisNode(asyncResp->res.jsonValue, chassisSubNode);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700571
Ed Tanousef4c65b2023-04-24 15:28:50 -0700572 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
573 "/redfish/v1/Chassis/{}/{}", chassisIdStr, chassisSubNode);
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500574
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500575 // Get the list of all sensors for this Chassis element
576 std::string sensorPath = *chassisPath + "/all_sensors";
George Liu6c3e9452023-03-03 13:55:29 +0800577 dbus::utility::getAssociationEndPoints(
578 sensorPath,
Ed Tanous7f1cc262022-08-09 13:33:57 -0700579 [asyncResp, chassisSubNode, sensorTypes,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700580 callback = std::forward<const Callback>(callback)](
Ed Tanous8b242752023-06-27 17:17:13 -0700581 const boost::system::error_code& ec2,
George Liu6c3e9452023-03-03 13:55:29 +0800582 const dbus::utility::MapperEndPoints& nodeSensorList) {
Ed Tanous8b242752023-06-27 17:17:13 -0700583 if (ec2)
Ed Tanous002d39b2022-05-31 08:59:27 -0700584 {
Ed Tanous8b242752023-06-27 17:17:13 -0700585 if (ec2.value() != EBADR)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700586 {
Ed Tanous7f1cc262022-08-09 13:33:57 -0700587 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -0700588 return;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700589 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700590 }
Nan Zhoufe04d492022-06-22 17:10:41 +0000591 const std::shared_ptr<std::set<std::string>> culledSensorList =
592 std::make_shared<std::set<std::string>>();
Ed Tanous7f1cc262022-08-09 13:33:57 -0700593 reduceSensorList(asyncResp->res, chassisSubNode, sensorTypes,
594 &nodeSensorList, culledSensorList);
Ed Tanous62598e32023-07-17 17:06:25 -0700595 BMCWEB_LOG_DEBUG("Finishing with {}", culledSensorList->size());
Ed Tanous002d39b2022-05-31 08:59:27 -0700596 callback(culledSensorList);
George Liu7a1dbc42022-12-07 16:03:22 +0800597 });
Patrick Williams5a39f772023-10-20 11:20:21 -0500598 });
Ed Tanous62598e32023-07-17 17:06:25 -0700599 BMCWEB_LOG_DEBUG("getChassis exit");
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100600}
601
602/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500603 * @brief Returns the Redfish State value for the specified inventory item.
604 * @param inventoryItem D-Bus inventory item associated with a sensor.
Matt Simmeringaaf08ac2023-10-04 08:41:01 -0700605 * @param sensorAvailable Boolean representing if D-Bus sensor is marked as
606 * available.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500607 * @return State value for inventory item.
James Feist34dd1792019-05-17 14:10:54 -0700608 */
Matt Simmeringaaf08ac2023-10-04 08:41:01 -0700609inline resource::State getState(const InventoryItem* inventoryItem,
610 const bool sensorAvailable)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500611{
612 if ((inventoryItem != nullptr) && !(inventoryItem->isPresent))
613 {
Matt Simmeringaaf08ac2023-10-04 08:41:01 -0700614 return resource::State::Absent;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500615 }
James Feist34dd1792019-05-17 14:10:54 -0700616
Matt Simmeringaaf08ac2023-10-04 08:41:01 -0700617 if (!sensorAvailable)
618 {
619 return resource::State::UnavailableOffline;
620 }
621
622 return resource::State::Enabled;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500623}
624
625/**
626 * @brief Returns the Redfish Health value for the specified sensor.
627 * @param sensorJson Sensor JSON object.
Ed Tanous1d7c0052022-08-09 12:32:26 -0700628 * @param valuesDict Map of all sensor DBus values.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500629 * @param inventoryItem D-Bus inventory item associated with the sensor. Will
630 * be nullptr if no associated inventory item was found.
631 * @return Health value for sensor.
632 */
Ed Tanous1d7c0052022-08-09 12:32:26 -0700633inline std::string getHealth(nlohmann::json& sensorJson,
634 const dbus::utility::DBusPropertiesMap& valuesDict,
635 const InventoryItem* inventoryItem)
James Feist34dd1792019-05-17 14:10:54 -0700636{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500637 // Get current health value (if any) in the sensor JSON object. Some JSON
638 // objects contain multiple sensors (such as PowerSupplies). We want to set
639 // the overall health to be the most severe of any of the sensors.
640 std::string currentHealth;
641 auto statusIt = sensorJson.find("Status");
642 if (statusIt != sensorJson.end())
643 {
644 auto healthIt = statusIt->find("Health");
645 if (healthIt != statusIt->end())
646 {
647 std::string* health = healthIt->get_ptr<std::string*>();
648 if (health != nullptr)
649 {
650 currentHealth = *health;
651 }
652 }
653 }
654
655 // If current health in JSON object is already Critical, return that. This
656 // should override the sensor health, which might be less severe.
657 if (currentHealth == "Critical")
658 {
659 return "Critical";
660 }
661
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200662 const bool* criticalAlarmHigh = nullptr;
663 const bool* criticalAlarmLow = nullptr;
664 const bool* warningAlarmHigh = nullptr;
665 const bool* warningAlarmLow = nullptr;
Ed Tanous711ac7a2021-12-20 09:34:41 -0800666
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200667 const bool success = sdbusplus::unpackPropertiesNoThrow(
668 dbus_utils::UnpackErrorPrinter(), valuesDict, "CriticalAlarmHigh",
669 criticalAlarmHigh, "CriticalAlarmLow", criticalAlarmLow,
670 "WarningAlarmHigh", warningAlarmHigh, "WarningAlarmLow",
671 warningAlarmLow);
672
673 if (success)
James Feist34dd1792019-05-17 14:10:54 -0700674 {
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200675 // Check if sensor has critical threshold alarm
676 if ((criticalAlarmHigh != nullptr && *criticalAlarmHigh) ||
677 (criticalAlarmLow != nullptr && *criticalAlarmLow))
James Feist34dd1792019-05-17 14:10:54 -0700678 {
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200679 return "Critical";
James Feist34dd1792019-05-17 14:10:54 -0700680 }
681 }
682
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500683 // Check if associated inventory item is not functional
684 if ((inventoryItem != nullptr) && !(inventoryItem->isFunctional))
685 {
686 return "Critical";
687 }
688
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200689 // If current health in JSON object is already Warning, return that. This
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500690 // should override the sensor status, which might be less severe.
691 if (currentHealth == "Warning")
692 {
693 return "Warning";
694 }
695
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200696 if (success)
James Feist34dd1792019-05-17 14:10:54 -0700697 {
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200698 // Check if sensor has warning threshold alarm
699 if ((warningAlarmHigh != nullptr && *warningAlarmHigh) ||
700 (warningAlarmLow != nullptr && *warningAlarmLow))
James Feist34dd1792019-05-17 14:10:54 -0700701 {
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200702 return "Warning";
James Feist34dd1792019-05-17 14:10:54 -0700703 }
704 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500705
James Feist34dd1792019-05-17 14:10:54 -0700706 return "OK";
707}
708
Ed Tanous23a21a12020-07-25 04:45:05 +0000709inline void setLedState(nlohmann::json& sensorJson,
Anthony Wilsond5005492019-07-31 16:34:17 -0500710 const InventoryItem* inventoryItem)
711{
712 if (inventoryItem != nullptr && !inventoryItem->ledObjectPath.empty())
713 {
714 switch (inventoryItem->ledState)
715 {
716 case LedState::OFF:
717 sensorJson["IndicatorLED"] = "Off";
718 break;
719 case LedState::ON:
720 sensorJson["IndicatorLED"] = "Lit";
721 break;
722 case LedState::BLINK:
723 sensorJson["IndicatorLED"] = "Blinking";
724 break;
Ed Tanous4da04902024-03-19 11:32:44 -0700725 default:
Anthony Wilsond5005492019-07-31 16:34:17 -0500726 break;
727 }
728 }
729}
730
James Feist34dd1792019-05-17 14:10:54 -0700731/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100732 * @brief Builds a json sensor representation of a sensor.
733 * @param sensorName The name of the sensor to be built
Gunnar Mills274fad52018-06-13 15:45:36 -0500734 * @param sensorType The type (temperature, fan_tach, etc) of the sensor to
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100735 * build
Ed Tanous8ece0e42024-01-02 13:16:50 -0800736 * @param chassisSubNode The subnode (thermal, sensor, etc) of the sensor
Ed Tanous1d7c0052022-08-09 12:32:26 -0700737 * @param propertiesDict A dictionary of the properties to build the sensor
738 * from.
739 * @param sensorJson The json object to fill
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500740 * @param inventoryItem D-Bus inventory item associated with the sensor. Will
741 * be nullptr if no associated inventory item was found.
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100742 */
Ed Tanous1d7c0052022-08-09 12:32:26 -0700743inline void objectPropertiesToJson(
744 std::string_view sensorName, std::string_view sensorType,
745 std::string_view chassisSubNode,
746 const dbus::utility::DBusPropertiesMap& propertiesDict,
Ed Tanous81ce6092020-12-17 16:54:55 +0000747 nlohmann::json& sensorJson, InventoryItem* inventoryItem)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700748{
Ed Tanous1d7c0052022-08-09 12:32:26 -0700749 if (chassisSubNode == sensors::node::sensors)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500750 {
Ed Tanousc71d6122022-11-29 14:10:32 -0800751 std::string subNodeEscaped(sensorType);
Ed Tanous3544d2a2023-08-06 18:12:20 -0700752 auto remove = std::ranges::remove(subNodeEscaped, '_');
753 subNodeEscaped.erase(std::ranges::begin(remove), subNodeEscaped.end());
Ed Tanousc1d019a2022-08-06 09:36:06 -0700754
755 // For sensors in SensorCollection we set Id instead of MemberId,
756 // including power sensors.
757 subNodeEscaped += '_';
758 subNodeEscaped += sensorName;
759 sensorJson["Id"] = std::move(subNodeEscaped);
760
Ed Tanous1d7c0052022-08-09 12:32:26 -0700761 std::string sensorNameEs(sensorName);
762 std::replace(sensorNameEs.begin(), sensorNameEs.end(), '_', ' ');
763 sensorJson["Name"] = std::move(sensorNameEs);
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500764 }
765 else if (sensorType != "power")
766 {
767 // Set MemberId and Name for non-power sensors. For PowerSupplies and
768 // PowerControl, those properties have more general values because
769 // multiple sensors can be stored in the same JSON object.
Ed Tanous1d7c0052022-08-09 12:32:26 -0700770 std::string sensorNameEs(sensorName);
771 std::replace(sensorNameEs.begin(), sensorNameEs.end(), '_', ' ');
772 sensorJson["Name"] = std::move(sensorNameEs);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500773 }
Ed Tanouse742b6c2019-05-03 15:06:53 -0700774
Matt Simmeringaaf08ac2023-10-04 08:41:01 -0700775 const bool* checkAvailable = nullptr;
776 bool available = true;
777 const bool success = sdbusplus::unpackPropertiesNoThrow(
778 dbus_utils::UnpackErrorPrinter(), propertiesDict, "Available",
779 checkAvailable);
780 if (!success)
781 {
782 messages::internalError();
783 }
784 if (checkAvailable != nullptr)
785 {
786 available = *checkAvailable;
787 }
788
789 sensorJson["Status"]["State"] = getState(inventoryItem, available);
Patrick Williams89492a12023-05-10 07:51:34 -0500790 sensorJson["Status"]["Health"] = getHealth(sensorJson, propertiesDict,
791 inventoryItem);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700792
793 // Parameter to set to override the type we get from dbus, and force it to
794 // int, regardless of what is available. This is used for schemas like fan,
795 // that require integers, not floats.
796 bool forceToInt = false;
797
Anthony Wilson3929aca2019-07-19 15:42:33 -0500798 nlohmann::json::json_pointer unit("/Reading");
Ed Tanous1d7c0052022-08-09 12:32:26 -0700799 if (chassisSubNode == sensors::node::sensors)
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500800 {
Shounak Mitra2a4ba192022-06-01 23:34:12 +0000801 sensorJson["@odata.type"] = "#Sensor.v1_2_0.Sensor";
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000802
Ed Tanous0ec8b832022-03-14 14:56:47 -0700803 sensor::ReadingType readingType = sensors::toReadingType(sensorType);
804 if (readingType == sensor::ReadingType::Invalid)
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500805 {
Ed Tanous62598e32023-07-17 17:06:25 -0700806 BMCWEB_LOG_ERROR("Redfish cannot map reading type for {}",
807 sensorType);
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500808 }
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000809 else
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500810 {
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000811 sensorJson["ReadingType"] = readingType;
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500812 }
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000813
Ed Tanous1d7c0052022-08-09 12:32:26 -0700814 std::string_view readingUnits = sensors::toReadingUnits(sensorType);
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000815 if (readingUnits.empty())
Adrian Ambrożewiczf8ede152020-06-02 13:26:33 +0200816 {
Ed Tanous62598e32023-07-17 17:06:25 -0700817 BMCWEB_LOG_ERROR("Redfish cannot map reading unit for {}",
818 sensorType);
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000819 }
820 else
821 {
822 sensorJson["ReadingUnits"] = readingUnits;
Adrian Ambrożewiczf8ede152020-06-02 13:26:33 +0200823 }
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500824 }
825 else if (sensorType == "temperature")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700826 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500827 unit = "/ReadingCelsius"_json_pointer;
Ed Tanous81ce6092020-12-17 16:54:55 +0000828 sensorJson["@odata.type"] = "#Thermal.v1_3_0.Temperature";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700829 // TODO(ed) Documentation says that path should be type fan_tach,
830 // implementation seems to implement fan
831 }
832 else if (sensorType == "fan" || sensorType == "fan_tach")
833 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500834 unit = "/Reading"_json_pointer;
Ed Tanous81ce6092020-12-17 16:54:55 +0000835 sensorJson["ReadingUnits"] = "RPM";
836 sensorJson["@odata.type"] = "#Thermal.v1_3_0.Fan";
837 setLedState(sensorJson, inventoryItem);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700838 forceToInt = true;
839 }
Ed Tanous6f6d0d32018-10-12 11:16:43 -0700840 else if (sensorType == "fan_pwm")
841 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500842 unit = "/Reading"_json_pointer;
Ed Tanous81ce6092020-12-17 16:54:55 +0000843 sensorJson["ReadingUnits"] = "Percent";
844 sensorJson["@odata.type"] = "#Thermal.v1_3_0.Fan";
845 setLedState(sensorJson, inventoryItem);
Ed Tanous6f6d0d32018-10-12 11:16:43 -0700846 forceToInt = true;
847 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700848 else if (sensorType == "voltage")
849 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500850 unit = "/ReadingVolts"_json_pointer;
Ed Tanous81ce6092020-12-17 16:54:55 +0000851 sensorJson["@odata.type"] = "#Power.v1_0_0.Voltage";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700852 }
Ed Tanous2474adf2018-09-05 16:31:16 -0700853 else if (sensorType == "power")
854 {
Ed Tanous18f8f602023-07-18 10:07:23 -0700855 std::string lower;
856 std::ranges::transform(sensorName, std::back_inserter(lower),
857 bmcweb::asciiToLower);
858 if (lower == "total_power")
Eddie James028f7eb2019-05-17 21:24:36 +0000859 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000860 sensorJson["@odata.type"] = "#Power.v1_0_0.PowerControl";
Gunnar Mills7ab06f42019-07-02 13:07:16 -0500861 // Put multiple "sensors" into a single PowerControl, so have
862 // generic names for MemberId and Name. Follows Redfish mockup.
Ed Tanous81ce6092020-12-17 16:54:55 +0000863 sensorJson["MemberId"] = "0";
864 sensorJson["Name"] = "Chassis Power Control";
Anthony Wilson3929aca2019-07-19 15:42:33 -0500865 unit = "/PowerConsumedWatts"_json_pointer;
Eddie James028f7eb2019-05-17 21:24:36 +0000866 }
Ed Tanous18f8f602023-07-18 10:07:23 -0700867 else if (lower.find("input") != std::string::npos)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700868 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500869 unit = "/PowerInputWatts"_json_pointer;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700870 }
871 else
872 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500873 unit = "/PowerOutputWatts"_json_pointer;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700874 }
Ed Tanous2474adf2018-09-05 16:31:16 -0700875 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700876 else
877 {
Ed Tanous62598e32023-07-17 17:06:25 -0700878 BMCWEB_LOG_ERROR("Redfish cannot map object type for {}", sensorName);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700879 return;
880 }
881 // Map of dbus interface name, dbus property name and redfish property_name
Anthony Wilson3929aca2019-07-19 15:42:33 -0500882 std::vector<
883 std::tuple<const char*, const char*, nlohmann::json::json_pointer>>
884 properties;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700885 properties.reserve(7);
886
887 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600888
Ed Tanous1d7c0052022-08-09 12:32:26 -0700889 if (chassisSubNode == sensors::node::sensors)
Anthony Wilson3929aca2019-07-19 15:42:33 -0500890 {
891 properties.emplace_back(
892 "xyz.openbmc_project.Sensor.Threshold.Warning", "WarningHigh",
893 "/Thresholds/UpperCaution/Reading"_json_pointer);
894 properties.emplace_back(
895 "xyz.openbmc_project.Sensor.Threshold.Warning", "WarningLow",
896 "/Thresholds/LowerCaution/Reading"_json_pointer);
897 properties.emplace_back(
898 "xyz.openbmc_project.Sensor.Threshold.Critical", "CriticalHigh",
899 "/Thresholds/UpperCritical/Reading"_json_pointer);
900 properties.emplace_back(
901 "xyz.openbmc_project.Sensor.Threshold.Critical", "CriticalLow",
902 "/Thresholds/LowerCritical/Reading"_json_pointer);
903 }
904 else if (sensorType != "power")
Shawn McCarneyde629b62019-03-08 10:42:51 -0600905 {
906 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500907 "WarningHigh",
908 "/UpperThresholdNonCritical"_json_pointer);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600909 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500910 "WarningLow",
911 "/LowerThresholdNonCritical"_json_pointer);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600912 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500913 "CriticalHigh",
914 "/UpperThresholdCritical"_json_pointer);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600915 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500916 "CriticalLow",
917 "/LowerThresholdCritical"_json_pointer);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600918 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700919
Ed Tanous2474adf2018-09-05 16:31:16 -0700920 // TODO Need to get UpperThresholdFatal and LowerThresholdFatal
921
Ed Tanous1d7c0052022-08-09 12:32:26 -0700922 if (chassisSubNode == sensors::node::sensors)
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500923 {
924 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500925 "/ReadingRangeMin"_json_pointer);
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500926 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500927 "/ReadingRangeMax"_json_pointer);
George Liu51c35a82022-10-13 20:22:14 +0800928 properties.emplace_back("xyz.openbmc_project.Sensor.Accuracy",
929 "Accuracy", "/Accuracy"_json_pointer);
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500930 }
931 else if (sensorType == "temperature")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700932 {
933 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500934 "/MinReadingRangeTemp"_json_pointer);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700935 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500936 "/MaxReadingRangeTemp"_json_pointer);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700937 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500938 else if (sensorType != "power")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700939 {
940 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500941 "/MinReadingRange"_json_pointer);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700942 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500943 "/MaxReadingRange"_json_pointer);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700944 }
945
Anthony Wilson3929aca2019-07-19 15:42:33 -0500946 for (const std::tuple<const char*, const char*,
947 nlohmann::json::json_pointer>& p : properties)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700948 {
Ed Tanous1d7c0052022-08-09 12:32:26 -0700949 for (const auto& [valueName, valueVariant] : propertiesDict)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700950 {
Ed Tanous1d7c0052022-08-09 12:32:26 -0700951 if (valueName != std::get<1>(p))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700952 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800953 continue;
954 }
Ed Tanous1d7c0052022-08-09 12:32:26 -0700955
956 // The property we want to set may be nested json, so use
957 // a json_pointer for easy indexing into the json structure.
958 const nlohmann::json::json_pointer& key = std::get<2>(p);
959
Ed Tanous1d7c0052022-08-09 12:32:26 -0700960 const double* doubleValue = std::get_if<double>(&valueVariant);
Ed Tanous40e4f382022-08-09 18:42:51 -0700961 if (doubleValue == nullptr)
Ed Tanous711ac7a2021-12-20 09:34:41 -0800962 {
Ed Tanous62598e32023-07-17 17:06:25 -0700963 BMCWEB_LOG_ERROR("Got value interface that wasn't double");
Ed Tanous1d7c0052022-08-09 12:32:26 -0700964 continue;
965 }
Ed Tanous283860f2022-08-29 14:08:50 -0700966 if (!std::isfinite(*doubleValue))
967 {
968 if (valueName == "Value")
969 {
970 // Readings are allowed to be NAN for unavailable; coerce
971 // them to null in the json response.
972 sensorJson[key] = nullptr;
973 continue;
974 }
Ed Tanous62598e32023-07-17 17:06:25 -0700975 BMCWEB_LOG_WARNING("Sensor value for {} was unexpectedly {}",
976 valueName, *doubleValue);
Ed Tanous283860f2022-08-29 14:08:50 -0700977 continue;
978 }
Ed Tanous1d7c0052022-08-09 12:32:26 -0700979 if (forceToInt)
980 {
Ed Tanous40e4f382022-08-09 18:42:51 -0700981 sensorJson[key] = static_cast<int64_t>(*doubleValue);
Ed Tanous1d7c0052022-08-09 12:32:26 -0700982 }
983 else
984 {
Ed Tanous40e4f382022-08-09 18:42:51 -0700985 sensorJson[key] = *doubleValue;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700986 }
987 }
988 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100989}
990
Ed Tanous1d7c0052022-08-09 12:32:26 -0700991/**
992 * @brief Builds a json sensor representation of a sensor.
993 * @param sensorName The name of the sensor to be built
994 * @param sensorType The type (temperature, fan_tach, etc) of the sensor to
995 * build
Ed Tanous8ece0e42024-01-02 13:16:50 -0800996 * @param chassisSubNode The subnode (thermal, sensor, etc) of the sensor
Ed Tanous1d7c0052022-08-09 12:32:26 -0700997 * @param interfacesDict A dictionary of the interfaces and properties of said
998 * interfaces to be built from
999 * @param sensorJson The json object to fill
1000 * @param inventoryItem D-Bus inventory item associated with the sensor. Will
1001 * be nullptr if no associated inventory item was found.
1002 */
1003inline void objectInterfacesToJson(
1004 const std::string& sensorName, const std::string& sensorType,
1005 const std::string& chassisSubNode,
Michael Shen80f79a42023-08-24 13:41:53 +00001006 const dbus::utility::DBusInterfacesMap& interfacesDict,
Ed Tanous1d7c0052022-08-09 12:32:26 -07001007 nlohmann::json& sensorJson, InventoryItem* inventoryItem)
1008{
Ed Tanous1d7c0052022-08-09 12:32:26 -07001009 for (const auto& [interface, valuesDict] : interfacesDict)
1010 {
1011 objectPropertiesToJson(sensorName, sensorType, chassisSubNode,
1012 valuesDict, sensorJson, inventoryItem);
1013 }
Ed Tanous62598e32023-07-17 17:06:25 -07001014 BMCWEB_LOG_DEBUG("Added sensor {}", sensorName);
Ed Tanous1d7c0052022-08-09 12:32:26 -07001015}
1016
Ed Tanousb5a76932020-09-29 16:16:58 -07001017inline void populateFanRedundancy(
1018 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
James Feist8bd25cc2019-03-15 15:14:00 -07001019{
George Liue99073f2022-12-09 11:06:16 +08001020 constexpr std::array<std::string_view, 1> interfaces = {
1021 "xyz.openbmc_project.Control.FanRedundancy"};
1022 dbus::utility::getSubTree(
1023 "/xyz/openbmc_project/control", 2, interfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001024 [sensorsAsyncResp](
George Liue99073f2022-12-09 11:06:16 +08001025 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001026 const dbus::utility::MapperGetSubTreeResponse& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001027 if (ec)
1028 {
1029 return; // don't have to have this interface
1030 }
George Liu6c3e9452023-03-03 13:55:29 +08001031 for (const std::pair<std::string, dbus::utility::MapperServiceMap>&
Ed Tanous002d39b2022-05-31 08:59:27 -07001032 pathPair : resp)
1033 {
1034 const std::string& path = pathPair.first;
George Liu6c3e9452023-03-03 13:55:29 +08001035 const dbus::utility::MapperServiceMap& objDict = pathPair.second;
Ed Tanous002d39b2022-05-31 08:59:27 -07001036 if (objDict.empty())
James Feist8bd25cc2019-03-15 15:14:00 -07001037 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001038 continue; // this should be impossible
James Feist8bd25cc2019-03-15 15:14:00 -07001039 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001040
1041 const std::string& owner = objDict.begin()->first;
George Liu6c3e9452023-03-03 13:55:29 +08001042 dbus::utility::getAssociationEndPoints(
1043 path + "/chassis",
1044 [path, owner, sensorsAsyncResp](
Ed Tanous8b242752023-06-27 17:17:13 -07001045 const boost::system::error_code& ec2,
George Liu6c3e9452023-03-03 13:55:29 +08001046 const dbus::utility::MapperEndPoints& endpoints) {
Ed Tanous8b242752023-06-27 17:17:13 -07001047 if (ec2)
James Feist8bd25cc2019-03-15 15:14:00 -07001048 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001049 return; // if they don't have an association we
1050 // can't tell what chassis is
James Feist8bd25cc2019-03-15 15:14:00 -07001051 }
Ed Tanous3544d2a2023-08-06 18:12:20 -07001052 auto found = std::ranges::find_if(
1053 endpoints, [sensorsAsyncResp](const std::string& entry) {
Patrick Williams5a39f772023-10-20 11:20:21 -05001054 return entry.find(sensorsAsyncResp->chassisId) !=
1055 std::string::npos;
1056 });
James Feist8bd25cc2019-03-15 15:14:00 -07001057
Ed Tanous002d39b2022-05-31 08:59:27 -07001058 if (found == endpoints.end())
1059 {
1060 return;
1061 }
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +02001062 sdbusplus::asio::getAllProperties(
1063 *crow::connections::systemBus, owner, path,
1064 "xyz.openbmc_project.Control.FanRedundancy",
Ed Tanous002d39b2022-05-31 08:59:27 -07001065 [path, sensorsAsyncResp](
Ed Tanous8b242752023-06-27 17:17:13 -07001066 const boost::system::error_code& ec3,
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +02001067 const dbus::utility::DBusPropertiesMap& ret) {
Ed Tanous8b242752023-06-27 17:17:13 -07001068 if (ec3)
Ed Tanous002d39b2022-05-31 08:59:27 -07001069 {
1070 return; // don't have to have this
1071 // interface
1072 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001073
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +02001074 const uint8_t* allowedFailures = nullptr;
1075 const std::vector<std::string>* collection = nullptr;
1076 const std::string* status = nullptr;
1077
1078 const bool success = sdbusplus::unpackPropertiesNoThrow(
1079 dbus_utils::UnpackErrorPrinter(), ret,
1080 "AllowedFailures", allowedFailures, "Collection",
1081 collection, "Status", status);
1082
1083 if (!success)
1084 {
1085 messages::internalError(
1086 sensorsAsyncResp->asyncResp->res);
1087 return;
1088 }
1089
1090 if (allowedFailures == nullptr || collection == nullptr ||
1091 status == nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07001092 {
Ed Tanous62598e32023-07-17 17:06:25 -07001093 BMCWEB_LOG_ERROR("Invalid redundancy interface");
Ed Tanous002d39b2022-05-31 08:59:27 -07001094 messages::internalError(
1095 sensorsAsyncResp->asyncResp->res);
1096 return;
1097 }
1098
Ed Tanous002d39b2022-05-31 08:59:27 -07001099 sdbusplus::message::object_path objectPath(path);
1100 std::string name = objectPath.filename();
1101 if (name.empty())
1102 {
1103 // this should be impossible
1104 messages::internalError(
1105 sensorsAsyncResp->asyncResp->res);
1106 return;
1107 }
Ed Tanous18f8f602023-07-18 10:07:23 -07001108 std::ranges::replace(name, '_', ' ');
Ed Tanous002d39b2022-05-31 08:59:27 -07001109
1110 std::string health;
1111
Ed Tanous11ba3972022-07-11 09:50:41 -07001112 if (status->ends_with("Full"))
Ed Tanous002d39b2022-05-31 08:59:27 -07001113 {
1114 health = "OK";
1115 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001116 else if (status->ends_with("Degraded"))
Ed Tanous002d39b2022-05-31 08:59:27 -07001117 {
1118 health = "Warning";
1119 }
1120 else
1121 {
1122 health = "Critical";
1123 }
1124 nlohmann::json::array_t redfishCollection;
1125 const auto& fanRedfish =
1126 sensorsAsyncResp->asyncResp->res.jsonValue["Fans"];
1127 for (const std::string& item : *collection)
1128 {
Ed Tanous8a592812022-06-04 09:06:59 -07001129 sdbusplus::message::object_path itemPath(item);
1130 std::string itemName = itemPath.filename();
Ed Tanous002d39b2022-05-31 08:59:27 -07001131 if (itemName.empty())
James Feist8bd25cc2019-03-15 15:14:00 -07001132 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001133 continue;
James Feist8bd25cc2019-03-15 15:14:00 -07001134 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001135 /*
1136 todo(ed): merge patch that fixes the names
1137 std::replace(itemName.begin(),
1138 itemName.end(), '_', ' ');*/
Ed Tanous3544d2a2023-08-06 18:12:20 -07001139 auto schemaItem = std::ranges::find_if(
1140 fanRedfish, [itemName](const nlohmann::json& fan) {
Patrick Williams5a39f772023-10-20 11:20:21 -05001141 return fan["Name"] == itemName;
1142 });
Ed Tanous002d39b2022-05-31 08:59:27 -07001143 if (schemaItem != fanRedfish.end())
James Feist8bd25cc2019-03-15 15:14:00 -07001144 {
Ed Tanous8a592812022-06-04 09:06:59 -07001145 nlohmann::json::object_t collectionId;
1146 collectionId["@odata.id"] =
Ed Tanous002d39b2022-05-31 08:59:27 -07001147 (*schemaItem)["@odata.id"];
1148 redfishCollection.emplace_back(
Ed Tanous8a592812022-06-04 09:06:59 -07001149 std::move(collectionId));
Ed Tanous002d39b2022-05-31 08:59:27 -07001150 }
1151 else
1152 {
Ed Tanous62598e32023-07-17 17:06:25 -07001153 BMCWEB_LOG_ERROR("failed to find fan in schema");
Ed Tanous002d39b2022-05-31 08:59:27 -07001154 messages::internalError(
1155 sensorsAsyncResp->asyncResp->res);
James Feist8bd25cc2019-03-15 15:14:00 -07001156 return;
1157 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001158 }
James Feist8bd25cc2019-03-15 15:14:00 -07001159
Patrick Williams89492a12023-05-10 07:51:34 -05001160 size_t minNumNeeded = collection->empty()
1161 ? 0
1162 : collection->size() -
1163 *allowedFailures;
Ed Tanous002d39b2022-05-31 08:59:27 -07001164 nlohmann::json& jResp = sensorsAsyncResp->asyncResp->res
1165 .jsonValue["Redundancy"];
James Feist8bd25cc2019-03-15 15:14:00 -07001166
Ed Tanous002d39b2022-05-31 08:59:27 -07001167 nlohmann::json::object_t redundancy;
Ed Tanousef4c65b2023-04-24 15:28:50 -07001168 boost::urls::url url =
1169 boost::urls::format("/redfish/v1/Chassis/{}/{}",
1170 sensorsAsyncResp->chassisId,
1171 sensorsAsyncResp->chassisSubNode);
Willy Tueddfc432022-09-26 16:46:38 +00001172 url.set_fragment(("/Redundancy"_json_pointer / jResp.size())
1173 .to_string());
1174 redundancy["@odata.id"] = std::move(url);
Ed Tanous002d39b2022-05-31 08:59:27 -07001175 redundancy["@odata.type"] = "#Redundancy.v1_3_2.Redundancy";
1176 redundancy["MinNumNeeded"] = minNumNeeded;
Ed Tanous002d39b2022-05-31 08:59:27 -07001177 redundancy["Mode"] = "N+m";
1178 redundancy["Name"] = name;
1179 redundancy["RedundancySet"] = redfishCollection;
1180 redundancy["Status"]["Health"] = health;
1181 redundancy["Status"]["State"] = "Enabled";
James Feist8bd25cc2019-03-15 15:14:00 -07001182
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001183 jResp.emplace_back(std::move(redundancy));
Ed Tanous002d39b2022-05-31 08:59:27 -07001184 });
Patrick Williams5a39f772023-10-20 11:20:21 -05001185 });
Ed Tanous002d39b2022-05-31 08:59:27 -07001186 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001187 });
James Feist8bd25cc2019-03-15 15:14:00 -07001188}
1189
Ed Tanousb5a76932020-09-29 16:16:58 -07001190inline void
Ed Tanous81ce6092020-12-17 16:54:55 +00001191 sortJSONResponse(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001192{
zhanghch058d1b46d2021-04-01 11:18:24 +08001193 nlohmann::json& response = sensorsAsyncResp->asyncResp->res.jsonValue;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001194 std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
Ed Tanous81ce6092020-12-17 16:54:55 +00001195 if (sensorsAsyncResp->chassisSubNode == sensors::node::power)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001196 {
1197 sensorHeaders = {"Voltages", "PowerSupplies"};
1198 }
1199 for (const std::string& sensorGroup : sensorHeaders)
1200 {
1201 nlohmann::json::iterator entry = response.find(sensorGroup);
1202 if (entry != response.end())
1203 {
1204 std::sort(entry->begin(), entry->end(),
Ed Tanous02cad962022-06-30 16:50:15 -07001205 [](const nlohmann::json& c1, const nlohmann::json& c2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001206 return c1["Name"] < c2["Name"];
1207 });
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001208
1209 // add the index counts to the end of each entry
1210 size_t count = 0;
1211 for (nlohmann::json& sensorJson : *entry)
1212 {
1213 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
1214 if (odata == sensorJson.end())
1215 {
1216 continue;
1217 }
1218 std::string* value = odata->get_ptr<std::string*>();
1219 if (value != nullptr)
1220 {
Willy Tueddfc432022-09-26 16:46:38 +00001221 *value += "/" + std::to_string(count);
George Liu3e35c762023-03-08 16:56:38 +08001222 sensorJson["MemberId"] = std::to_string(count);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001223 count++;
Ed Tanous81ce6092020-12-17 16:54:55 +00001224 sensorsAsyncResp->updateUri(sensorJson["Name"], *value);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001225 }
1226 }
1227 }
1228 }
1229}
1230
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01001231/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001232 * @brief Finds the inventory item with the specified object path.
1233 * @param inventoryItems D-Bus inventory items associated with sensors.
1234 * @param invItemObjPath D-Bus object path of inventory item.
1235 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001236 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001237inline InventoryItem* findInventoryItem(
Ed Tanousb5a76932020-09-29 16:16:58 -07001238 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001239 const std::string& invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001240{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001241 for (InventoryItem& inventoryItem : *inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001242 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001243 if (inventoryItem.objectPath == invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001244 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001245 return &inventoryItem;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001246 }
1247 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001248 return nullptr;
1249}
1250
1251/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001252 * @brief Finds the inventory item associated with the specified sensor.
1253 * @param inventoryItems D-Bus inventory items associated with sensors.
1254 * @param sensorObjPath D-Bus object path of sensor.
1255 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001256 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001257inline InventoryItem* findInventoryItemForSensor(
Ed Tanousb5a76932020-09-29 16:16:58 -07001258 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001259 const std::string& sensorObjPath)
1260{
1261 for (InventoryItem& inventoryItem : *inventoryItems)
1262 {
Ed Tanousdb0d36e2023-06-30 10:37:05 -07001263 if (inventoryItem.sensors.contains(sensorObjPath))
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001264 {
1265 return &inventoryItem;
1266 }
1267 }
1268 return nullptr;
1269}
1270
1271/**
Anthony Wilsond5005492019-07-31 16:34:17 -05001272 * @brief Finds the inventory item associated with the specified led path.
1273 * @param inventoryItems D-Bus inventory items associated with sensors.
1274 * @param ledObjPath D-Bus object path of led.
1275 * @return Inventory item within vector, or nullptr if no match found.
1276 */
1277inline InventoryItem*
1278 findInventoryItemForLed(std::vector<InventoryItem>& inventoryItems,
1279 const std::string& ledObjPath)
1280{
1281 for (InventoryItem& inventoryItem : inventoryItems)
1282 {
1283 if (inventoryItem.ledObjectPath == ledObjPath)
1284 {
1285 return &inventoryItem;
1286 }
1287 }
1288 return nullptr;
1289}
1290
1291/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001292 * @brief Adds inventory item and associated sensor to specified vector.
1293 *
1294 * Adds a new InventoryItem to the vector if necessary. Searches for an
1295 * existing InventoryItem with the specified object path. If not found, one is
1296 * added to the vector.
1297 *
1298 * Next, the specified sensor is added to the set of sensors associated with the
1299 * InventoryItem.
1300 *
1301 * @param inventoryItems D-Bus inventory items associated with sensors.
1302 * @param invItemObjPath D-Bus object path of inventory item.
1303 * @param sensorObjPath D-Bus object path of sensor
1304 */
Ed Tanousb5a76932020-09-29 16:16:58 -07001305inline void addInventoryItem(
1306 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
1307 const std::string& invItemObjPath, const std::string& sensorObjPath)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001308{
1309 // Look for inventory item in vector
Patrick Williams89492a12023-05-10 07:51:34 -05001310 InventoryItem* inventoryItem = findInventoryItem(inventoryItems,
1311 invItemObjPath);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001312
1313 // If inventory item doesn't exist in vector, add it
1314 if (inventoryItem == nullptr)
1315 {
1316 inventoryItems->emplace_back(invItemObjPath);
1317 inventoryItem = &(inventoryItems->back());
1318 }
1319
1320 // Add sensor to set of sensors associated with inventory item
1321 inventoryItem->sensors.emplace(sensorObjPath);
1322}
1323
1324/**
1325 * @brief Stores D-Bus data in the specified inventory item.
1326 *
1327 * Finds D-Bus data in the specified map of interfaces. Stores the data in the
1328 * specified InventoryItem.
1329 *
1330 * This data is later used to provide sensor property values in the JSON
1331 * response.
1332 *
1333 * @param inventoryItem Inventory item where data will be stored.
1334 * @param interfacesDict Map containing D-Bus interfaces and their properties
1335 * for the specified inventory item.
1336 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001337inline void storeInventoryItemData(
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001338 InventoryItem& inventoryItem,
Michael Shen80f79a42023-08-24 13:41:53 +00001339 const dbus::utility::DBusInterfacesMap& interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001340{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001341 // Get properties from Inventory.Item interface
Ed Tanous711ac7a2021-12-20 09:34:41 -08001342
Ed Tanous9eb808c2022-01-25 10:19:23 -08001343 for (const auto& [interface, values] : interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001344 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001345 if (interface == "xyz.openbmc_project.Inventory.Item")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001346 {
Ed Tanous9eb808c2022-01-25 10:19:23 -08001347 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001348 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001349 if (name == "Present")
1350 {
1351 const bool* value = std::get_if<bool>(&dbusValue);
1352 if (value != nullptr)
1353 {
1354 inventoryItem.isPresent = *value;
1355 }
1356 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001357 }
1358 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001359 // Check if Inventory.Item.PowerSupply interface is present
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001360
Ed Tanous711ac7a2021-12-20 09:34:41 -08001361 if (interface == "xyz.openbmc_project.Inventory.Item.PowerSupply")
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001362 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001363 inventoryItem.isPowerSupply = true;
1364 }
1365
1366 // Get properties from Inventory.Decorator.Asset interface
1367 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
1368 {
Ed Tanous9eb808c2022-01-25 10:19:23 -08001369 for (const auto& [name, dbusValue] : values)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001370 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001371 if (name == "Manufacturer")
1372 {
1373 const std::string* value =
1374 std::get_if<std::string>(&dbusValue);
1375 if (value != nullptr)
1376 {
1377 inventoryItem.manufacturer = *value;
1378 }
1379 }
1380 if (name == "Model")
1381 {
1382 const std::string* value =
1383 std::get_if<std::string>(&dbusValue);
1384 if (value != nullptr)
1385 {
1386 inventoryItem.model = *value;
1387 }
1388 }
1389 if (name == "SerialNumber")
1390 {
1391 const std::string* value =
1392 std::get_if<std::string>(&dbusValue);
1393 if (value != nullptr)
1394 {
1395 inventoryItem.serialNumber = *value;
1396 }
1397 }
1398 if (name == "PartNumber")
1399 {
1400 const std::string* value =
1401 std::get_if<std::string>(&dbusValue);
1402 if (value != nullptr)
1403 {
1404 inventoryItem.partNumber = *value;
1405 }
1406 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001407 }
1408 }
1409
Ed Tanous711ac7a2021-12-20 09:34:41 -08001410 if (interface ==
1411 "xyz.openbmc_project.State.Decorator.OperationalStatus")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001412 {
Ed Tanous9eb808c2022-01-25 10:19:23 -08001413 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001414 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001415 if (name == "Functional")
1416 {
1417 const bool* value = std::get_if<bool>(&dbusValue);
1418 if (value != nullptr)
1419 {
1420 inventoryItem.isFunctional = *value;
1421 }
1422 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001423 }
1424 }
1425 }
1426}
1427
1428/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001429 * @brief Gets D-Bus data for inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001430 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001431 * Uses the specified connections (services) to obtain D-Bus data for inventory
1432 * items associated with sensors. Stores the resulting data in the
1433 * inventoryItems vector.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001434 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001435 * This data is later used to provide sensor property values in the JSON
1436 * response.
1437 *
1438 * Finds the inventory item data asynchronously. Invokes callback when data has
1439 * been obtained.
1440 *
1441 * The callback must have the following signature:
1442 * @code
Anthony Wilsond5005492019-07-31 16:34:17 -05001443 * callback(void)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001444 * @endcode
1445 *
1446 * This function is called recursively, obtaining data asynchronously from one
1447 * connection in each call. This ensures the callback is not invoked until the
1448 * last asynchronous function has completed.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001449 *
1450 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001451 * @param inventoryItems D-Bus inventory items associated with sensors.
1452 * @param invConnections Connections that provide data for the inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001453 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001454 * @param callback Callback to invoke when inventory data has been obtained.
1455 * @param invConnectionsIndex Current index in invConnections. Only specified
1456 * in recursive calls to this function.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001457 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001458template <typename Callback>
1459static void getInventoryItemsData(
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001460 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001461 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Ed Tanousd0090732022-10-04 17:22:56 -07001462 std::shared_ptr<std::set<std::string>> invConnections, Callback&& callback,
1463 size_t invConnectionsIndex = 0)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001464{
Ed Tanous62598e32023-07-17 17:06:25 -07001465 BMCWEB_LOG_DEBUG("getInventoryItemsData enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001466
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001467 // If no more connections left, call callback
1468 if (invConnectionsIndex >= invConnections->size())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001469 {
Anthony Wilsond5005492019-07-31 16:34:17 -05001470 callback();
Ed Tanous62598e32023-07-17 17:06:25 -07001471 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001472 return;
1473 }
1474
1475 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +00001476 auto it = invConnections->begin();
1477 std::advance(it, invConnectionsIndex);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001478 if (it != invConnections->end())
1479 {
1480 const std::string& invConnection = *it;
1481
George Liu5eb468d2023-06-20 17:03:24 +08001482 // Get all object paths and their interfaces for current connection
1483 sdbusplus::message::object_path path("/xyz/openbmc_project/inventory");
1484 dbus::utility::getManagedObjects(
1485 invConnection, path,
1486 [sensorsAsyncResp, inventoryItems, invConnections,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001487 callback = std::forward<Callback>(callback), invConnectionsIndex](
George Liu5eb468d2023-06-20 17:03:24 +08001488 const boost::system::error_code& ec,
1489 const dbus::utility::ManagedObjectType& resp) {
Ed Tanous62598e32023-07-17 17:06:25 -07001490 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001491 if (ec)
1492 {
Ed Tanous62598e32023-07-17 17:06:25 -07001493 BMCWEB_LOG_ERROR(
1494 "getInventoryItemsData respHandler DBus error {}", ec);
zhanghch058d1b46d2021-04-01 11:18:24 +08001495 messages::internalError(sensorsAsyncResp->asyncResp->res);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001496 return;
1497 }
1498
1499 // Loop through returned object paths
1500 for (const auto& objDictEntry : resp)
1501 {
1502 const std::string& objPath =
1503 static_cast<const std::string&>(objDictEntry.first);
1504
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001505 // If this object path is one of the specified inventory items
Patrick Williams89492a12023-05-10 07:51:34 -05001506 InventoryItem* inventoryItem = findInventoryItem(inventoryItems,
1507 objPath);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001508 if (inventoryItem != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001509 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001510 // Store inventory data in InventoryItem
1511 storeInventoryItemData(*inventoryItem, objDictEntry.second);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001512 }
1513 }
1514
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001515 // Recurse to get inventory item data from next connection
1516 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
Ed Tanousd0090732022-10-04 17:22:56 -07001517 invConnections, std::move(callback),
1518 invConnectionsIndex + 1);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001519
Ed Tanous62598e32023-07-17 17:06:25 -07001520 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler exit");
Patrick Williams5a39f772023-10-20 11:20:21 -05001521 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001522 }
1523
Ed Tanous62598e32023-07-17 17:06:25 -07001524 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001525}
1526
1527/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001528 * @brief Gets connections that provide D-Bus data for inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001529 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001530 * Gets the D-Bus connections (services) that provide data for the inventory
1531 * items that are associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001532 *
1533 * Finds the connections asynchronously. Invokes callback when information has
1534 * been obtained.
1535 *
1536 * The callback must have the following signature:
1537 * @code
Nan Zhoufe04d492022-06-22 17:10:41 +00001538 * callback(std::shared_ptr<std::set<std::string>> invConnections)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001539 * @endcode
1540 *
1541 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001542 * @param inventoryItems D-Bus inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001543 * @param callback Callback to invoke when connections have been obtained.
1544 */
1545template <typename Callback>
1546static void getInventoryItemsConnections(
Ed Tanousb5a76932020-09-29 16:16:58 -07001547 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1548 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001549 Callback&& callback)
1550{
Ed Tanous62598e32023-07-17 17:06:25 -07001551 BMCWEB_LOG_DEBUG("getInventoryItemsConnections enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001552
1553 const std::string path = "/xyz/openbmc_project/inventory";
George Liue99073f2022-12-09 11:06:16 +08001554 constexpr std::array<std::string_view, 4> interfaces = {
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001555 "xyz.openbmc_project.Inventory.Item",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001556 "xyz.openbmc_project.Inventory.Item.PowerSupply",
1557 "xyz.openbmc_project.Inventory.Decorator.Asset",
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001558 "xyz.openbmc_project.State.Decorator.OperationalStatus"};
1559
George Liue99073f2022-12-09 11:06:16 +08001560 // Make call to ObjectMapper to find all inventory items
1561 dbus::utility::getSubTree(
1562 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001563 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001564 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001565 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001566 const dbus::utility::MapperGetSubTreeResponse& subtree) {
George Liue99073f2022-12-09 11:06:16 +08001567 // Response handler for parsing output from GetSubTree
Ed Tanous62598e32023-07-17 17:06:25 -07001568 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001569 if (ec)
1570 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001571 messages::internalError(sensorsAsyncResp->asyncResp->res);
Ed Tanous62598e32023-07-17 17:06:25 -07001572 BMCWEB_LOG_ERROR(
1573 "getInventoryItemsConnections respHandler DBus error {}", ec);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001574 return;
1575 }
1576
1577 // Make unique list of connections for desired inventory items
Nan Zhoufe04d492022-06-22 17:10:41 +00001578 std::shared_ptr<std::set<std::string>> invConnections =
1579 std::make_shared<std::set<std::string>>();
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001580
1581 // Loop through objects from GetSubTree
1582 for (const std::pair<
1583 std::string,
1584 std::vector<std::pair<std::string, std::vector<std::string>>>>&
1585 object : subtree)
1586 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001587 // Check if object path is one of the specified inventory items
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001588 const std::string& objPath = object.first;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001589 if (findInventoryItem(inventoryItems, objPath) != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001590 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001591 // Store all connections to inventory item
1592 for (const std::pair<std::string, std::vector<std::string>>&
1593 objData : object.second)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001594 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001595 const std::string& invConnection = objData.first;
1596 invConnections->insert(invConnection);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001597 }
1598 }
1599 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001600
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001601 callback(invConnections);
Ed Tanous62598e32023-07-17 17:06:25 -07001602 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler exit");
Patrick Williams5a39f772023-10-20 11:20:21 -05001603 });
Ed Tanous62598e32023-07-17 17:06:25 -07001604 BMCWEB_LOG_DEBUG("getInventoryItemsConnections exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001605}
1606
1607/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001608 * @brief Gets associations from sensors to inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001609 *
1610 * Looks for ObjectMapper associations from the specified sensors to related
Anthony Wilsond5005492019-07-31 16:34:17 -05001611 * inventory items. Then finds the associations from those inventory items to
1612 * their LEDs, if any.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001613 *
1614 * Finds the inventory items asynchronously. Invokes callback when information
1615 * has been obtained.
1616 *
1617 * The callback must have the following signature:
1618 * @code
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001619 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001620 * @endcode
1621 *
1622 * @param sensorsAsyncResp Pointer to object holding response data.
1623 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001624 * implements ObjectManager.
1625 * @param callback Callback to invoke when inventory items have been obtained.
1626 */
1627template <typename Callback>
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001628static void getInventoryItemAssociations(
Ed Tanousb5a76932020-09-29 16:16:58 -07001629 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001630 const std::shared_ptr<std::set<std::string>>& sensorNames,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001631 Callback&& callback)
1632{
Ed Tanous62598e32023-07-17 17:06:25 -07001633 BMCWEB_LOG_DEBUG("getInventoryItemAssociations enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001634
George Liu5eb468d2023-06-20 17:03:24 +08001635 // Call GetManagedObjects on the ObjectMapper to get all associations
1636 sdbusplus::message::object_path path("/");
1637 dbus::utility::getManagedObjects(
1638 "xyz.openbmc_project.ObjectMapper", path,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001639 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001640 sensorNames](const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -07001641 const dbus::utility::ManagedObjectType& resp) {
Ed Tanous62598e32023-07-17 17:06:25 -07001642 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001643 if (ec)
1644 {
Ed Tanous62598e32023-07-17 17:06:25 -07001645 BMCWEB_LOG_ERROR(
1646 "getInventoryItemAssociations respHandler DBus error {}", ec);
zhanghch058d1b46d2021-04-01 11:18:24 +08001647 messages::internalError(sensorsAsyncResp->asyncResp->res);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001648 return;
1649 }
1650
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001651 // Create vector to hold list of inventory items
1652 std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1653 std::make_shared<std::vector<InventoryItem>>();
1654
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001655 // Loop through returned object paths
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001656 std::string sensorAssocPath;
1657 sensorAssocPath.reserve(128); // avoid memory allocations
1658 for (const auto& objDictEntry : resp)
1659 {
1660 const std::string& objPath =
1661 static_cast<const std::string&>(objDictEntry.first);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001662
1663 // If path is inventory association for one of the specified sensors
1664 for (const std::string& sensorName : *sensorNames)
1665 {
1666 sensorAssocPath = sensorName;
1667 sensorAssocPath += "/inventory";
1668 if (objPath == sensorAssocPath)
1669 {
1670 // Get Association interface for object path
Ed Tanous711ac7a2021-12-20 09:34:41 -08001671 for (const auto& [interface, values] : objDictEntry.second)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001672 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001673 if (interface == "xyz.openbmc_project.Association")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001674 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001675 for (const auto& [valueName, value] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001676 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001677 if (valueName == "endpoints")
1678 {
1679 const std::vector<std::string>* endpoints =
1680 std::get_if<std::vector<std::string>>(
1681 &value);
1682 if ((endpoints != nullptr) &&
1683 !endpoints->empty())
1684 {
1685 // Add inventory item to vector
1686 const std::string& invItemPath =
1687 endpoints->front();
1688 addInventoryItem(inventoryItems,
1689 invItemPath,
1690 sensorName);
1691 }
1692 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001693 }
1694 }
1695 }
1696 break;
1697 }
1698 }
1699 }
1700
Anthony Wilsond5005492019-07-31 16:34:17 -05001701 // Now loop through the returned object paths again, this time to
1702 // find the leds associated with the inventory items we just found
1703 std::string inventoryAssocPath;
1704 inventoryAssocPath.reserve(128); // avoid memory allocations
1705 for (const auto& objDictEntry : resp)
1706 {
1707 const std::string& objPath =
1708 static_cast<const std::string&>(objDictEntry.first);
Anthony Wilsond5005492019-07-31 16:34:17 -05001709
1710 for (InventoryItem& inventoryItem : *inventoryItems)
1711 {
1712 inventoryAssocPath = inventoryItem.objectPath;
1713 inventoryAssocPath += "/leds";
1714 if (objPath == inventoryAssocPath)
1715 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001716 for (const auto& [interface, values] : objDictEntry.second)
Anthony Wilsond5005492019-07-31 16:34:17 -05001717 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001718 if (interface == "xyz.openbmc_project.Association")
Anthony Wilsond5005492019-07-31 16:34:17 -05001719 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001720 for (const auto& [valueName, value] : values)
Anthony Wilsond5005492019-07-31 16:34:17 -05001721 {
Ed Tanous711ac7a2021-12-20 09:34:41 -08001722 if (valueName == "endpoints")
1723 {
1724 const std::vector<std::string>* endpoints =
1725 std::get_if<std::vector<std::string>>(
1726 &value);
1727 if ((endpoints != nullptr) &&
1728 !endpoints->empty())
1729 {
1730 // Add inventory item to vector
1731 // Store LED path in inventory item
1732 const std::string& ledPath =
1733 endpoints->front();
1734 inventoryItem.ledObjectPath = ledPath;
1735 }
1736 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001737 }
1738 }
1739 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001740
Anthony Wilsond5005492019-07-31 16:34:17 -05001741 break;
1742 }
1743 }
1744 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001745 callback(inventoryItems);
Ed Tanous62598e32023-07-17 17:06:25 -07001746 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler exit");
Patrick Williams5a39f772023-10-20 11:20:21 -05001747 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001748
Ed Tanous62598e32023-07-17 17:06:25 -07001749 BMCWEB_LOG_DEBUG("getInventoryItemAssociations exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001750}
1751
1752/**
Anthony Wilsond5005492019-07-31 16:34:17 -05001753 * @brief Gets D-Bus data for inventory item leds associated with sensors.
1754 *
1755 * Uses the specified connections (services) to obtain D-Bus data for inventory
1756 * item leds associated with sensors. Stores the resulting data in the
1757 * inventoryItems vector.
1758 *
1759 * This data is later used to provide sensor property values in the JSON
1760 * response.
1761 *
1762 * Finds the inventory item led data asynchronously. Invokes callback when data
1763 * has been obtained.
1764 *
1765 * The callback must have the following signature:
1766 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001767 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001768 * @endcode
1769 *
1770 * This function is called recursively, obtaining data asynchronously from one
1771 * connection in each call. This ensures the callback is not invoked until the
1772 * last asynchronous function has completed.
1773 *
1774 * @param sensorsAsyncResp Pointer to object holding response data.
1775 * @param inventoryItems D-Bus inventory items associated with sensors.
1776 * @param ledConnections Connections that provide data for the inventory leds.
1777 * @param callback Callback to invoke when inventory data has been obtained.
1778 * @param ledConnectionsIndex Current index in ledConnections. Only specified
1779 * in recursive calls to this function.
1780 */
1781template <typename Callback>
1782void getInventoryLedData(
1783 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1784 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001785 std::shared_ptr<std::map<std::string, std::string>> ledConnections,
Anthony Wilsond5005492019-07-31 16:34:17 -05001786 Callback&& callback, size_t ledConnectionsIndex = 0)
1787{
Ed Tanous62598e32023-07-17 17:06:25 -07001788 BMCWEB_LOG_DEBUG("getInventoryLedData enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001789
1790 // If no more connections left, call callback
1791 if (ledConnectionsIndex >= ledConnections->size())
1792 {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001793 callback();
Ed Tanous62598e32023-07-17 17:06:25 -07001794 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001795 return;
1796 }
1797
1798 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +00001799 auto it = ledConnections->begin();
1800 std::advance(it, ledConnectionsIndex);
Anthony Wilsond5005492019-07-31 16:34:17 -05001801 if (it != ledConnections->end())
1802 {
1803 const std::string& ledPath = (*it).first;
1804 const std::string& ledConnection = (*it).second;
1805 // Response handler for Get State property
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001806 auto respHandler =
1807 [sensorsAsyncResp, inventoryItems, ledConnections, ledPath,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001808 callback = std::forward<Callback>(callback), ledConnectionsIndex](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001809 const boost::system::error_code& ec, const std::string& state) {
Ed Tanous62598e32023-07-17 17:06:25 -07001810 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler enter");
Ed Tanous002d39b2022-05-31 08:59:27 -07001811 if (ec)
1812 {
Ed Tanous62598e32023-07-17 17:06:25 -07001813 BMCWEB_LOG_ERROR(
1814 "getInventoryLedData respHandler DBus error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07001815 messages::internalError(sensorsAsyncResp->asyncResp->res);
1816 return;
1817 }
1818
Ed Tanous62598e32023-07-17 17:06:25 -07001819 BMCWEB_LOG_DEBUG("Led state: {}", state);
Ed Tanous002d39b2022-05-31 08:59:27 -07001820 // Find inventory item with this LED object path
1821 InventoryItem* inventoryItem =
1822 findInventoryItemForLed(*inventoryItems, ledPath);
1823 if (inventoryItem != nullptr)
1824 {
1825 // Store LED state in InventoryItem
Ed Tanous11ba3972022-07-11 09:50:41 -07001826 if (state.ends_with("On"))
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001827 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001828 inventoryItem->ledState = LedState::ON;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001829 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001830 else if (state.ends_with("Blink"))
Anthony Wilsond5005492019-07-31 16:34:17 -05001831 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001832 inventoryItem->ledState = LedState::BLINK;
Anthony Wilsond5005492019-07-31 16:34:17 -05001833 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001834 else if (state.ends_with("Off"))
Ed Tanous002d39b2022-05-31 08:59:27 -07001835 {
1836 inventoryItem->ledState = LedState::OFF;
1837 }
1838 else
1839 {
1840 inventoryItem->ledState = LedState::UNKNOWN;
1841 }
1842 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001843
Ed Tanous002d39b2022-05-31 08:59:27 -07001844 // Recurse to get LED data from next connection
1845 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1846 ledConnections, std::move(callback),
1847 ledConnectionsIndex + 1);
Anthony Wilsond5005492019-07-31 16:34:17 -05001848
Ed Tanous62598e32023-07-17 17:06:25 -07001849 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler exit");
Ed Tanous002d39b2022-05-31 08:59:27 -07001850 };
Anthony Wilsond5005492019-07-31 16:34:17 -05001851
1852 // Get the State property for the current LED
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001853 sdbusplus::asio::getProperty<std::string>(
1854 *crow::connections::systemBus, ledConnection, ledPath,
1855 "xyz.openbmc_project.Led.Physical", "State",
1856 std::move(respHandler));
Anthony Wilsond5005492019-07-31 16:34:17 -05001857 }
1858
Ed Tanous62598e32023-07-17 17:06:25 -07001859 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001860}
1861
1862/**
1863 * @brief Gets LED data for LEDs associated with given inventory items.
1864 *
1865 * Gets the D-Bus connections (services) that provide LED data for the LEDs
1866 * associated with the specified inventory items. Then gets the LED data from
1867 * each connection and stores it in the inventory item.
1868 *
1869 * This data is later used to provide sensor property values in the JSON
1870 * response.
1871 *
1872 * Finds the LED data asynchronously. Invokes callback when information has
1873 * been obtained.
1874 *
1875 * The callback must have the following signature:
1876 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001877 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001878 * @endcode
1879 *
1880 * @param sensorsAsyncResp Pointer to object holding response data.
1881 * @param inventoryItems D-Bus inventory items associated with sensors.
1882 * @param callback Callback to invoke when inventory items have been obtained.
1883 */
1884template <typename Callback>
1885void getInventoryLeds(
1886 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1887 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1888 Callback&& callback)
1889{
Ed Tanous62598e32023-07-17 17:06:25 -07001890 BMCWEB_LOG_DEBUG("getInventoryLeds enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001891
1892 const std::string path = "/xyz/openbmc_project";
George Liue99073f2022-12-09 11:06:16 +08001893 constexpr std::array<std::string_view, 1> interfaces = {
Anthony Wilsond5005492019-07-31 16:34:17 -05001894 "xyz.openbmc_project.Led.Physical"};
1895
George Liue99073f2022-12-09 11:06:16 +08001896 // Make call to ObjectMapper to find all inventory items
1897 dbus::utility::getSubTree(
1898 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001899 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001900 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001901 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001902 const dbus::utility::MapperGetSubTreeResponse& subtree) {
George Liue99073f2022-12-09 11:06:16 +08001903 // Response handler for parsing output from GetSubTree
Ed Tanous62598e32023-07-17 17:06:25 -07001904 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001905 if (ec)
1906 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001907 messages::internalError(sensorsAsyncResp->asyncResp->res);
Ed Tanous62598e32023-07-17 17:06:25 -07001908 BMCWEB_LOG_ERROR("getInventoryLeds respHandler DBus error {}", ec);
Anthony Wilsond5005492019-07-31 16:34:17 -05001909 return;
1910 }
1911
1912 // Build map of LED object paths to connections
Nan Zhoufe04d492022-06-22 17:10:41 +00001913 std::shared_ptr<std::map<std::string, std::string>> ledConnections =
1914 std::make_shared<std::map<std::string, std::string>>();
Anthony Wilsond5005492019-07-31 16:34:17 -05001915
1916 // Loop through objects from GetSubTree
1917 for (const std::pair<
1918 std::string,
1919 std::vector<std::pair<std::string, std::vector<std::string>>>>&
1920 object : subtree)
1921 {
1922 // Check if object path is LED for one of the specified inventory
1923 // items
1924 const std::string& ledPath = object.first;
1925 if (findInventoryItemForLed(*inventoryItems, ledPath) != nullptr)
1926 {
1927 // Add mapping from ledPath to connection
1928 const std::string& connection = object.second.begin()->first;
1929 (*ledConnections)[ledPath] = connection;
Ed Tanous62598e32023-07-17 17:06:25 -07001930 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", ledPath, connection);
Anthony Wilsond5005492019-07-31 16:34:17 -05001931 }
1932 }
1933
1934 getInventoryLedData(sensorsAsyncResp, inventoryItems, ledConnections,
1935 std::move(callback));
Ed Tanous62598e32023-07-17 17:06:25 -07001936 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler exit");
Patrick Williams5a39f772023-10-20 11:20:21 -05001937 });
Ed Tanous62598e32023-07-17 17:06:25 -07001938 BMCWEB_LOG_DEBUG("getInventoryLeds exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001939}
1940
1941/**
Gunnar Mills42cbe532019-08-15 15:26:54 -05001942 * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent
1943 *
1944 * Uses the specified connections (services) (currently assumes just one) to
1945 * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in
1946 * the inventoryItems vector. Only stores data in Power Supply inventoryItems.
1947 *
1948 * This data is later used to provide sensor property values in the JSON
1949 * response.
1950 *
1951 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1952 * when data has been obtained.
1953 *
1954 * The callback must have the following signature:
1955 * @code
1956 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1957 * @endcode
1958 *
1959 * @param sensorsAsyncResp Pointer to object holding response data.
1960 * @param inventoryItems D-Bus inventory items associated with sensors.
1961 * @param psAttributesConnections Connections that provide data for the Power
1962 * Supply Attributes
1963 * @param callback Callback to invoke when data has been obtained.
1964 */
1965template <typename Callback>
1966void getPowerSupplyAttributesData(
Ed Tanousb5a76932020-09-29 16:16:58 -07001967 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001968 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001969 const std::map<std::string, std::string>& psAttributesConnections,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001970 Callback&& callback)
1971{
Ed Tanous62598e32023-07-17 17:06:25 -07001972 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001973
1974 if (psAttributesConnections.empty())
1975 {
Ed Tanous62598e32023-07-17 17:06:25 -07001976 BMCWEB_LOG_DEBUG("Can't find PowerSupplyAttributes, no connections!");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001977 callback(inventoryItems);
1978 return;
1979 }
1980
1981 // Assuming just one connection (service) for now
Nan Zhoufe04d492022-06-22 17:10:41 +00001982 auto it = psAttributesConnections.begin();
Gunnar Mills42cbe532019-08-15 15:26:54 -05001983
1984 const std::string& psAttributesPath = (*it).first;
1985 const std::string& psAttributesConnection = (*it).second;
1986
1987 // Response handler for Get DeratingFactor property
Patrick Williams5a39f772023-10-20 11:20:21 -05001988 auto respHandler = [sensorsAsyncResp, inventoryItems,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001989 callback = std::forward<Callback>(callback)](
Patrick Williams5a39f772023-10-20 11:20:21 -05001990 const boost::system::error_code& ec,
1991 const uint32_t value) {
Ed Tanous62598e32023-07-17 17:06:25 -07001992 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001993 if (ec)
1994 {
Ed Tanous62598e32023-07-17 17:06:25 -07001995 BMCWEB_LOG_ERROR(
1996 "getPowerSupplyAttributesData respHandler DBus error {}", ec);
zhanghch058d1b46d2021-04-01 11:18:24 +08001997 messages::internalError(sensorsAsyncResp->asyncResp->res);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001998 return;
1999 }
2000
Ed Tanous62598e32023-07-17 17:06:25 -07002001 BMCWEB_LOG_DEBUG("PS EfficiencyPercent value: {}", value);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07002002 // Store value in Power Supply Inventory Items
2003 for (InventoryItem& inventoryItem : *inventoryItems)
Gunnar Mills42cbe532019-08-15 15:26:54 -05002004 {
Ed Tanous55f79e62022-01-25 11:26:16 -08002005 if (inventoryItem.isPowerSupply)
Gunnar Mills42cbe532019-08-15 15:26:54 -05002006 {
Jonathan Doman1e1e5982021-06-11 09:36:17 -07002007 inventoryItem.powerSupplyEfficiencyPercent =
2008 static_cast<int>(value);
Gunnar Mills42cbe532019-08-15 15:26:54 -05002009 }
2010 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05002011
Ed Tanous62598e32023-07-17 17:06:25 -07002012 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05002013 callback(inventoryItems);
2014 };
2015
2016 // Get the DeratingFactor property for the PowerSupplyAttributes
2017 // Currently only property on the interface/only one we care about
Jonathan Doman1e1e5982021-06-11 09:36:17 -07002018 sdbusplus::asio::getProperty<uint32_t>(
2019 *crow::connections::systemBus, psAttributesConnection, psAttributesPath,
2020 "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
2021 std::move(respHandler));
Gunnar Mills42cbe532019-08-15 15:26:54 -05002022
Ed Tanous62598e32023-07-17 17:06:25 -07002023 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05002024}
2025
2026/**
2027 * @brief Gets the Power Supply Attributes such as EfficiencyPercent
2028 *
2029 * Gets the D-Bus connection (service) that provides Power Supply Attributes
2030 * data. Then gets the Power Supply Attributes data from the connection
2031 * (currently just assumes 1 connection) and stores the data in the inventory
2032 * item.
2033 *
2034 * This data is later used to provide sensor property values in the JSON
2035 * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish.
2036 *
2037 * Finds the Power Supply Attributes data asynchronously. Invokes callback
2038 * when information has been obtained.
2039 *
2040 * The callback must have the following signature:
2041 * @code
2042 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
2043 * @endcode
2044 *
2045 * @param sensorsAsyncResp Pointer to object holding response data.
2046 * @param inventoryItems D-Bus inventory items associated with sensors.
2047 * @param callback Callback to invoke when data has been obtained.
2048 */
2049template <typename Callback>
2050void getPowerSupplyAttributes(
2051 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
2052 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
2053 Callback&& callback)
2054{
Ed Tanous62598e32023-07-17 17:06:25 -07002055 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05002056
2057 // Only need the power supply attributes when the Power Schema
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002058 if (sensorsAsyncResp->chassisSubNode != sensors::node::power)
Gunnar Mills42cbe532019-08-15 15:26:54 -05002059 {
Ed Tanous62598e32023-07-17 17:06:25 -07002060 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit since not Power");
Gunnar Mills42cbe532019-08-15 15:26:54 -05002061 callback(inventoryItems);
2062 return;
2063 }
2064
George Liue99073f2022-12-09 11:06:16 +08002065 constexpr std::array<std::string_view, 1> interfaces = {
Gunnar Mills42cbe532019-08-15 15:26:54 -05002066 "xyz.openbmc_project.Control.PowerSupplyAttributes"};
2067
George Liue99073f2022-12-09 11:06:16 +08002068 // Make call to ObjectMapper to find the PowerSupplyAttributes service
2069 dbus::utility::getSubTree(
2070 "/xyz/openbmc_project", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07002071 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanousb9d36b42022-02-26 21:42:46 -08002072 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08002073 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08002074 const dbus::utility::MapperGetSubTreeResponse& subtree) {
George Liue99073f2022-12-09 11:06:16 +08002075 // Response handler for parsing output from GetSubTree
Ed Tanous62598e32023-07-17 17:06:25 -07002076 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler enter");
Ed Tanous002d39b2022-05-31 08:59:27 -07002077 if (ec)
2078 {
2079 messages::internalError(sensorsAsyncResp->asyncResp->res);
Ed Tanous62598e32023-07-17 17:06:25 -07002080 BMCWEB_LOG_ERROR(
2081 "getPowerSupplyAttributes respHandler DBus error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07002082 return;
2083 }
2084 if (subtree.empty())
2085 {
Ed Tanous62598e32023-07-17 17:06:25 -07002086 BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
Ed Tanous002d39b2022-05-31 08:59:27 -07002087 callback(inventoryItems);
2088 return;
2089 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05002090
Ed Tanous002d39b2022-05-31 08:59:27 -07002091 // Currently we only support 1 power supply attribute, use this for
2092 // all the power supplies. Build map of object path to connection.
2093 // Assume just 1 connection and 1 path for now.
Nan Zhoufe04d492022-06-22 17:10:41 +00002094 std::map<std::string, std::string> psAttributesConnections;
Gunnar Mills42cbe532019-08-15 15:26:54 -05002095
Ed Tanous002d39b2022-05-31 08:59:27 -07002096 if (subtree[0].first.empty() || subtree[0].second.empty())
2097 {
Ed Tanous62598e32023-07-17 17:06:25 -07002098 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
Ed Tanous002d39b2022-05-31 08:59:27 -07002099 callback(inventoryItems);
2100 return;
2101 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05002102
Ed Tanous002d39b2022-05-31 08:59:27 -07002103 const std::string& psAttributesPath = subtree[0].first;
2104 const std::string& connection = subtree[0].second.begin()->first;
Gunnar Mills42cbe532019-08-15 15:26:54 -05002105
Ed Tanous002d39b2022-05-31 08:59:27 -07002106 if (connection.empty())
2107 {
Ed Tanous62598e32023-07-17 17:06:25 -07002108 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
Ed Tanous002d39b2022-05-31 08:59:27 -07002109 callback(inventoryItems);
2110 return;
2111 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05002112
Ed Tanous002d39b2022-05-31 08:59:27 -07002113 psAttributesConnections[psAttributesPath] = connection;
Ed Tanous62598e32023-07-17 17:06:25 -07002114 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", psAttributesPath,
2115 connection);
Gunnar Mills42cbe532019-08-15 15:26:54 -05002116
Ed Tanous002d39b2022-05-31 08:59:27 -07002117 getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems,
2118 psAttributesConnections,
2119 std::move(callback));
Ed Tanous62598e32023-07-17 17:06:25 -07002120 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler exit");
Patrick Williams5a39f772023-10-20 11:20:21 -05002121 });
Ed Tanous62598e32023-07-17 17:06:25 -07002122 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05002123}
2124
2125/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002126 * @brief Gets inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002127 *
2128 * Finds the inventory items that are associated with the specified sensors.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002129 * Then gets D-Bus data for the inventory items, such as presence and VPD.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002130 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002131 * This data is later used to provide sensor property values in the JSON
2132 * response.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002133 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002134 * Finds the inventory items asynchronously. Invokes callback when the
2135 * inventory items have been obtained.
2136 *
2137 * The callback must have the following signature:
2138 * @code
2139 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
2140 * @endcode
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002141 *
2142 * @param sensorsAsyncResp Pointer to object holding response data.
2143 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002144 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002145 * @param callback Callback to invoke when inventory items have been obtained.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002146 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002147template <typename Callback>
Ed Tanousd0090732022-10-04 17:22:56 -07002148static void
2149 getInventoryItems(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
2150 const std::shared_ptr<std::set<std::string>> sensorNames,
2151 Callback&& callback)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002152{
Ed Tanous62598e32023-07-17 17:06:25 -07002153 BMCWEB_LOG_DEBUG("getInventoryItems enter");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002154 auto getInventoryItemAssociationsCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -07002155 [sensorsAsyncResp, callback = std::forward<Callback>(callback)](
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002156 std::shared_ptr<std::vector<InventoryItem>> inventoryItems) {
Ed Tanous62598e32023-07-17 17:06:25 -07002157 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb enter");
Ed Tanous002d39b2022-05-31 08:59:27 -07002158 auto getInventoryItemsConnectionsCb =
Ed Tanousd0090732022-10-04 17:22:56 -07002159 [sensorsAsyncResp, inventoryItems,
Ed Tanous8cb2c022024-03-27 16:31:46 -07002160 callback = std::forward<const Callback>(callback)](
Nan Zhoufe04d492022-06-22 17:10:41 +00002161 std::shared_ptr<std::set<std::string>> invConnections) {
Ed Tanous62598e32023-07-17 17:06:25 -07002162 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb enter");
Ed Tanous002d39b2022-05-31 08:59:27 -07002163 auto getInventoryItemsDataCb = [sensorsAsyncResp, inventoryItems,
2164 callback{std::move(callback)}]() {
Ed Tanous62598e32023-07-17 17:06:25 -07002165 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05002166
Ed Tanous002d39b2022-05-31 08:59:27 -07002167 auto getInventoryLedsCb = [sensorsAsyncResp, inventoryItems,
2168 callback{std::move(callback)}]() {
Ed Tanous62598e32023-07-17 17:06:25 -07002169 BMCWEB_LOG_DEBUG("getInventoryLedsCb enter");
Ed Tanous002d39b2022-05-31 08:59:27 -07002170 // Find Power Supply Attributes and get the data
2171 getPowerSupplyAttributes(sensorsAsyncResp, inventoryItems,
2172 std::move(callback));
Ed Tanous62598e32023-07-17 17:06:25 -07002173 BMCWEB_LOG_DEBUG("getInventoryLedsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002174 };
2175
Ed Tanous002d39b2022-05-31 08:59:27 -07002176 // Find led connections and get the data
2177 getInventoryLeds(sensorsAsyncResp, inventoryItems,
2178 std::move(getInventoryLedsCb));
Ed Tanous62598e32023-07-17 17:06:25 -07002179 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb exit");
Ed Tanous002d39b2022-05-31 08:59:27 -07002180 };
2181
2182 // Get inventory item data from connections
2183 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
Ed Tanousd0090732022-10-04 17:22:56 -07002184 invConnections,
Ed Tanous002d39b2022-05-31 08:59:27 -07002185 std::move(getInventoryItemsDataCb));
Ed Tanous62598e32023-07-17 17:06:25 -07002186 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002187 };
2188
Ed Tanous002d39b2022-05-31 08:59:27 -07002189 // Get connections that provide inventory item data
2190 getInventoryItemsConnections(sensorsAsyncResp, inventoryItems,
2191 std::move(getInventoryItemsConnectionsCb));
Ed Tanous62598e32023-07-17 17:06:25 -07002192 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb exit");
Ed Tanous002d39b2022-05-31 08:59:27 -07002193 };
2194
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002195 // Get associations from sensors to inventory items
Ed Tanousd0090732022-10-04 17:22:56 -07002196 getInventoryItemAssociations(sensorsAsyncResp, sensorNames,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002197 std::move(getInventoryItemAssociationsCb));
Ed Tanous62598e32023-07-17 17:06:25 -07002198 BMCWEB_LOG_DEBUG("getInventoryItems exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002199}
2200
2201/**
2202 * @brief Returns JSON PowerSupply object for the specified inventory item.
2203 *
2204 * Searches for a JSON PowerSupply object that matches the specified inventory
2205 * item. If one is not found, a new PowerSupply object is added to the JSON
2206 * array.
2207 *
2208 * Multiple sensors are often associated with one power supply inventory item.
2209 * As a result, multiple sensor values are stored in one JSON PowerSupply
2210 * object.
2211 *
2212 * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
2213 * @param inventoryItem Inventory item for the power supply.
2214 * @param chassisId Chassis that contains the power supply.
2215 * @return JSON PowerSupply object for the specified inventory item.
2216 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002217inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002218 const InventoryItem& inventoryItem,
2219 const std::string& chassisId)
2220{
Ed Tanous18f8f602023-07-18 10:07:23 -07002221 std::string nameS;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01002222 nameS.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07002223 std::ranges::replace_copy(inventoryItem.name, nameS.begin(), '_', ' ');
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002224 // Check if matching PowerSupply object already exists in JSON array
2225 for (nlohmann::json& powerSupply : powerSupplyArray)
2226 {
Ed Tanous18f8f602023-07-18 10:07:23 -07002227 nlohmann::json::iterator nameIt = powerSupply.find("Name");
2228 if (nameIt == powerSupply.end())
2229 {
2230 continue;
2231 }
2232 const std::string* name = nameIt->get_ptr<std::string*>();
2233 if (name == nullptr)
2234 {
2235 continue;
2236 }
2237 if (nameS == *name)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002238 {
2239 return powerSupply;
2240 }
2241 }
2242
2243 // Add new PowerSupply object to JSON array
2244 powerSupplyArray.push_back({});
2245 nlohmann::json& powerSupply = powerSupplyArray.back();
Ed Tanousef4c65b2023-04-24 15:28:50 -07002246 boost::urls::url url = boost::urls::format("/redfish/v1/Chassis/{}/Power",
2247 chassisId);
Willy Tueddfc432022-09-26 16:46:38 +00002248 url.set_fragment(("/PowerSupplies"_json_pointer).to_string());
2249 powerSupply["@odata.id"] = std::move(url);
Ed Tanous18f8f602023-07-18 10:07:23 -07002250 std::string escaped;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01002251 escaped.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07002252 std::ranges::replace_copy(inventoryItem.name, escaped.begin(), '_', ' ');
2253 powerSupply["Name"] = std::move(escaped);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002254 powerSupply["Manufacturer"] = inventoryItem.manufacturer;
2255 powerSupply["Model"] = inventoryItem.model;
2256 powerSupply["PartNumber"] = inventoryItem.partNumber;
2257 powerSupply["SerialNumber"] = inventoryItem.serialNumber;
Anthony Wilsond5005492019-07-31 16:34:17 -05002258 setLedState(powerSupply, &inventoryItem);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002259
Gunnar Mills42cbe532019-08-15 15:26:54 -05002260 if (inventoryItem.powerSupplyEfficiencyPercent >= 0)
2261 {
2262 powerSupply["EfficiencyPercent"] =
2263 inventoryItem.powerSupplyEfficiencyPercent;
2264 }
2265
Matt Simmeringaaf08ac2023-10-04 08:41:01 -07002266 powerSupply["Status"]["State"] = getState(&inventoryItem, true);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002267 const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
2268 powerSupply["Status"]["Health"] = health;
2269
2270 return powerSupply;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002271}
2272
2273/**
Shawn McCarneyde629b62019-03-08 10:42:51 -06002274 * @brief Gets the values of the specified sensors.
2275 *
2276 * Stores the results as JSON in the SensorsAsyncResp.
2277 *
2278 * Gets the sensor values asynchronously. Stores the results later when the
2279 * information has been obtained.
2280 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002281 * The sensorNames set contains all requested sensors for the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06002282 *
2283 * To minimize the number of DBus calls, the DBus method
2284 * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
2285 * values of all sensors provided by a connection (service).
2286 *
2287 * The connections set contains all the connections that provide sensor values.
2288 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002289 * The InventoryItem vector contains D-Bus inventory items associated with the
2290 * sensors. Inventory item data is needed for some Redfish sensor properties.
2291 *
Shawn McCarneyde629b62019-03-08 10:42:51 -06002292 * @param SensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002293 * @param sensorNames All requested sensors within the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06002294 * @param connections Connections that provide sensor values.
Shawn McCarneyde629b62019-03-08 10:42:51 -06002295 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002296 * @param inventoryItems Inventory items associated with the sensors.
Shawn McCarneyde629b62019-03-08 10:42:51 -06002297 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002298inline void getSensorData(
Ed Tanous81ce6092020-12-17 16:54:55 +00002299 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00002300 const std::shared_ptr<std::set<std::string>>& sensorNames,
2301 const std::set<std::string>& connections,
Ed Tanousb5a76932020-09-29 16:16:58 -07002302 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems)
Shawn McCarneyde629b62019-03-08 10:42:51 -06002303{
Ed Tanous62598e32023-07-17 17:06:25 -07002304 BMCWEB_LOG_DEBUG("getSensorData enter");
Shawn McCarneyde629b62019-03-08 10:42:51 -06002305 // Get managed objects from all services exposing sensors
2306 for (const std::string& connection : connections)
2307 {
George Liu5eb468d2023-06-20 17:03:24 +08002308 sdbusplus::message::object_path sensorPath(
2309 "/xyz/openbmc_project/sensors");
2310 dbus::utility::getManagedObjects(
2311 connection, sensorPath,
Ed Tanous002d39b2022-05-31 08:59:27 -07002312 [sensorsAsyncResp, sensorNames,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002313 inventoryItems](const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -07002314 const dbus::utility::ManagedObjectType& resp) {
Ed Tanous62598e32023-07-17 17:06:25 -07002315 BMCWEB_LOG_DEBUG("getManagedObjectsCb enter");
Shawn McCarneyde629b62019-03-08 10:42:51 -06002316 if (ec)
2317 {
Ed Tanous62598e32023-07-17 17:06:25 -07002318 BMCWEB_LOG_ERROR("getManagedObjectsCb DBUS error: {}", ec);
zhanghch058d1b46d2021-04-01 11:18:24 +08002319 messages::internalError(sensorsAsyncResp->asyncResp->res);
Shawn McCarneyde629b62019-03-08 10:42:51 -06002320 return;
2321 }
2322 // Go through all objects and update response with sensor data
2323 for (const auto& objDictEntry : resp)
2324 {
2325 const std::string& objPath =
2326 static_cast<const std::string&>(objDictEntry.first);
Ed Tanous62598e32023-07-17 17:06:25 -07002327 BMCWEB_LOG_DEBUG("getManagedObjectsCb parsing object {}",
2328 objPath);
Shawn McCarneyde629b62019-03-08 10:42:51 -06002329
Shawn McCarneyde629b62019-03-08 10:42:51 -06002330 std::vector<std::string> split;
2331 // Reserve space for
2332 // /xyz/openbmc_project/sensors/<name>/<subname>
2333 split.reserve(6);
Ed Tanous50ebd4a2023-01-19 19:03:17 -08002334 // NOLINTNEXTLINE
2335 bmcweb::split(split, objPath, '/');
Shawn McCarneyde629b62019-03-08 10:42:51 -06002336 if (split.size() < 6)
2337 {
Ed Tanous62598e32023-07-17 17:06:25 -07002338 BMCWEB_LOG_ERROR("Got path that isn't long enough {}",
2339 objPath);
Shawn McCarneyde629b62019-03-08 10:42:51 -06002340 continue;
2341 }
Ed Tanous50ebd4a2023-01-19 19:03:17 -08002342 // These indexes aren't intuitive, as split puts an empty
Shawn McCarneyde629b62019-03-08 10:42:51 -06002343 // string at the beginning
2344 const std::string& sensorType = split[4];
2345 const std::string& sensorName = split[5];
Ed Tanous62598e32023-07-17 17:06:25 -07002346 BMCWEB_LOG_DEBUG("sensorName {} sensorType {}", sensorName,
2347 sensorType);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002348 if (sensorNames->find(objPath) == sensorNames->end())
Shawn McCarneyde629b62019-03-08 10:42:51 -06002349 {
Ed Tanous62598e32023-07-17 17:06:25 -07002350 BMCWEB_LOG_DEBUG("{} not in sensor list ", sensorName);
Shawn McCarneyde629b62019-03-08 10:42:51 -06002351 continue;
2352 }
2353
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002354 // Find inventory item (if any) associated with sensor
2355 InventoryItem* inventoryItem =
2356 findInventoryItemForSensor(inventoryItems, objPath);
2357
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002358 const std::string& sensorSchema =
Ed Tanous81ce6092020-12-17 16:54:55 +00002359 sensorsAsyncResp->chassisSubNode;
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002360
2361 nlohmann::json* sensorJson = nullptr;
2362
Nan Zhou928fefb2022-03-28 08:45:00 -07002363 if (sensorSchema == sensors::node::sensors &&
2364 !sensorsAsyncResp->efficientExpand)
Shawn McCarneyde629b62019-03-08 10:42:51 -06002365 {
Ed Tanousc1d019a2022-08-06 09:36:06 -07002366 std::string sensorTypeEscaped(sensorType);
Ed Tanous3544d2a2023-08-06 18:12:20 -07002367 auto remove = std::ranges::remove(sensorTypeEscaped, '_');
2368
2369 sensorTypeEscaped.erase(std::ranges::begin(remove),
2370 sensorTypeEscaped.end());
Ed Tanousc1d019a2022-08-06 09:36:06 -07002371 std::string sensorId(sensorTypeEscaped);
2372 sensorId += "_";
2373 sensorId += sensorName;
2374
zhanghch058d1b46d2021-04-01 11:18:24 +08002375 sensorsAsyncResp->asyncResp->res.jsonValue["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -07002376 boost::urls::format("/redfish/v1/Chassis/{}/{}/{}",
2377 sensorsAsyncResp->chassisId,
2378 sensorsAsyncResp->chassisSubNode,
2379 sensorId);
zhanghch058d1b46d2021-04-01 11:18:24 +08002380 sensorJson = &(sensorsAsyncResp->asyncResp->res.jsonValue);
Shawn McCarneyde629b62019-03-08 10:42:51 -06002381 }
2382 else
2383 {
Ed Tanous271584a2019-07-09 16:24:22 -07002384 std::string fieldName;
Nan Zhou928fefb2022-03-28 08:45:00 -07002385 if (sensorsAsyncResp->efficientExpand)
2386 {
2387 fieldName = "Members";
2388 }
2389 else if (sensorType == "temperature")
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002390 {
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002391 fieldName = "Temperatures";
2392 }
2393 else if (sensorType == "fan" || sensorType == "fan_tach" ||
2394 sensorType == "fan_pwm")
2395 {
2396 fieldName = "Fans";
2397 }
2398 else if (sensorType == "voltage")
2399 {
2400 fieldName = "Voltages";
2401 }
2402 else if (sensorType == "power")
2403 {
Ed Tanous55f79e62022-01-25 11:26:16 -08002404 if (sensorName == "total_power")
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002405 {
2406 fieldName = "PowerControl";
2407 }
2408 else if ((inventoryItem != nullptr) &&
2409 (inventoryItem->isPowerSupply))
2410 {
2411 fieldName = "PowerSupplies";
2412 }
2413 else
2414 {
2415 // Other power sensors are in SensorCollection
2416 continue;
2417 }
2418 }
2419 else
2420 {
Ed Tanous62598e32023-07-17 17:06:25 -07002421 BMCWEB_LOG_ERROR("Unsure how to handle sensorType {}",
2422 sensorType);
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002423 continue;
2424 }
2425
2426 nlohmann::json& tempArray =
zhanghch058d1b46d2021-04-01 11:18:24 +08002427 sensorsAsyncResp->asyncResp->res.jsonValue[fieldName];
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002428 if (fieldName == "PowerControl")
2429 {
2430 if (tempArray.empty())
2431 {
2432 // Put multiple "sensors" into a single
2433 // PowerControl. Follows MemberId naming and
2434 // naming in power.hpp.
Ed Tanous14766872022-03-15 10:44:42 -07002435 nlohmann::json::object_t power;
Ed Tanousef4c65b2023-04-24 15:28:50 -07002436 boost::urls::url url = boost::urls::format(
2437 "/redfish/v1/Chassis/{}/{}",
Willy Tueddfc432022-09-26 16:46:38 +00002438 sensorsAsyncResp->chassisId,
2439 sensorsAsyncResp->chassisSubNode);
2440 url.set_fragment((""_json_pointer / fieldName / "0")
2441 .to_string());
2442 power["@odata.id"] = std::move(url);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002443 tempArray.emplace_back(std::move(power));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002444 }
2445 sensorJson = &(tempArray.back());
2446 }
2447 else if (fieldName == "PowerSupplies")
2448 {
2449 if (inventoryItem != nullptr)
2450 {
2451 sensorJson =
2452 &(getPowerSupply(tempArray, *inventoryItem,
Ed Tanous81ce6092020-12-17 16:54:55 +00002453 sensorsAsyncResp->chassisId));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002454 }
2455 }
Nan Zhou928fefb2022-03-28 08:45:00 -07002456 else if (fieldName == "Members")
2457 {
Ed Tanous677bb752022-09-15 10:52:19 -07002458 std::string sensorTypeEscaped(sensorType);
Ed Tanous3544d2a2023-08-06 18:12:20 -07002459 auto remove = std::ranges::remove(sensorTypeEscaped,
2460 '_');
2461 sensorTypeEscaped.erase(std::ranges::begin(remove),
2462 sensorTypeEscaped.end());
Ed Tanous677bb752022-09-15 10:52:19 -07002463 std::string sensorId(sensorTypeEscaped);
2464 sensorId += "_";
2465 sensorId += sensorName;
2466
Ed Tanous14766872022-03-15 10:44:42 -07002467 nlohmann::json::object_t member;
Ed Tanousef4c65b2023-04-24 15:28:50 -07002468 member["@odata.id"] = boost::urls::format(
2469 "/redfish/v1/Chassis/{}/{}/{}",
Ed Tanous677bb752022-09-15 10:52:19 -07002470 sensorsAsyncResp->chassisId,
2471 sensorsAsyncResp->chassisSubNode, sensorId);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002472 tempArray.emplace_back(std::move(member));
Nan Zhou928fefb2022-03-28 08:45:00 -07002473 sensorJson = &(tempArray.back());
2474 }
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002475 else
2476 {
Ed Tanous14766872022-03-15 10:44:42 -07002477 nlohmann::json::object_t member;
Ed Tanousef4c65b2023-04-24 15:28:50 -07002478 boost::urls::url url = boost::urls::format(
2479 "/redfish/v1/Chassis/{}/{}",
Willy Tueddfc432022-09-26 16:46:38 +00002480 sensorsAsyncResp->chassisId,
2481 sensorsAsyncResp->chassisSubNode);
2482 url.set_fragment(
2483 (""_json_pointer / fieldName).to_string());
2484 member["@odata.id"] = std::move(url);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002485 tempArray.emplace_back(std::move(member));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002486 sensorJson = &(tempArray.back());
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002487 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002488 }
Shawn McCarneyde629b62019-03-08 10:42:51 -06002489
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002490 if (sensorJson != nullptr)
2491 {
Ed Tanous1d7c0052022-08-09 12:32:26 -07002492 objectInterfacesToJson(sensorName, sensorType,
2493 sensorsAsyncResp->chassisSubNode,
2494 objDictEntry.second, *sensorJson,
2495 inventoryItem);
2496
2497 std::string path = "/xyz/openbmc_project/sensors/";
2498 path += sensorType;
2499 path += "/";
2500 path += sensorName;
Ed Tanousc1d019a2022-08-06 09:36:06 -07002501 sensorsAsyncResp->addMetadata(*sensorJson, path);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002502 }
Shawn McCarneyde629b62019-03-08 10:42:51 -06002503 }
Ed Tanous81ce6092020-12-17 16:54:55 +00002504 if (sensorsAsyncResp.use_count() == 1)
James Feist8bd25cc2019-03-15 15:14:00 -07002505 {
Ed Tanous81ce6092020-12-17 16:54:55 +00002506 sortJSONResponse(sensorsAsyncResp);
Nan Zhou928fefb2022-03-28 08:45:00 -07002507 if (sensorsAsyncResp->chassisSubNode ==
2508 sensors::node::sensors &&
2509 sensorsAsyncResp->efficientExpand)
2510 {
2511 sensorsAsyncResp->asyncResp->res
2512 .jsonValue["Members@odata.count"] =
2513 sensorsAsyncResp->asyncResp->res.jsonValue["Members"]
2514 .size();
2515 }
2516 else if (sensorsAsyncResp->chassisSubNode ==
2517 sensors::node::thermal)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002518 {
Ed Tanous81ce6092020-12-17 16:54:55 +00002519 populateFanRedundancy(sensorsAsyncResp);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002520 }
James Feist8bd25cc2019-03-15 15:14:00 -07002521 }
Ed Tanous62598e32023-07-17 17:06:25 -07002522 BMCWEB_LOG_DEBUG("getManagedObjectsCb exit");
Patrick Williams5a39f772023-10-20 11:20:21 -05002523 });
Ed Tanous23a21a12020-07-25 04:45:05 +00002524 }
Ed Tanous62598e32023-07-17 17:06:25 -07002525 BMCWEB_LOG_DEBUG("getSensorData exit");
Shawn McCarneyde629b62019-03-08 10:42:51 -06002526}
2527
Nan Zhoufe04d492022-06-22 17:10:41 +00002528inline void
2529 processSensorList(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
2530 const std::shared_ptr<std::set<std::string>>& sensorNames)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002531{
Nan Zhoufe04d492022-06-22 17:10:41 +00002532 auto getConnectionCb = [sensorsAsyncResp, sensorNames](
2533 const std::set<std::string>& connections) {
Ed Tanous62598e32023-07-17 17:06:25 -07002534 BMCWEB_LOG_DEBUG("getConnectionCb enter");
Ed Tanousd0090732022-10-04 17:22:56 -07002535 auto getInventoryItemsCb =
2536 [sensorsAsyncResp, sensorNames,
2537 connections](const std::shared_ptr<std::vector<InventoryItem>>&
2538 inventoryItems) {
Ed Tanous62598e32023-07-17 17:06:25 -07002539 BMCWEB_LOG_DEBUG("getInventoryItemsCb enter");
Ed Tanousd0090732022-10-04 17:22:56 -07002540 // Get sensor data and store results in JSON
2541 getSensorData(sensorsAsyncResp, sensorNames, connections,
2542 inventoryItems);
Ed Tanous62598e32023-07-17 17:06:25 -07002543 BMCWEB_LOG_DEBUG("getInventoryItemsCb exit");
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002544 };
2545
Ed Tanousd0090732022-10-04 17:22:56 -07002546 // Get inventory items associated with sensors
2547 getInventoryItems(sensorsAsyncResp, sensorNames,
2548 std::move(getInventoryItemsCb));
2549
Ed Tanous62598e32023-07-17 17:06:25 -07002550 BMCWEB_LOG_DEBUG("getConnectionCb exit");
Ed Tanous002d39b2022-05-31 08:59:27 -07002551 };
2552
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002553 // Get set of connections that provide sensor values
Ed Tanous81ce6092020-12-17 16:54:55 +00002554 getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002555}
2556
Shawn McCarneyde629b62019-03-08 10:42:51 -06002557/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002558 * @brief Entry point for retrieving sensors data related to requested
2559 * chassis.
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02002560 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002561 */
Ed Tanousb5a76932020-09-29 16:16:58 -07002562inline void
Ed Tanous81ce6092020-12-17 16:54:55 +00002563 getChassisData(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002564{
Ed Tanous62598e32023-07-17 17:06:25 -07002565 BMCWEB_LOG_DEBUG("getChassisData enter");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002566 auto getChassisCb =
Ed Tanous81ce6092020-12-17 16:54:55 +00002567 [sensorsAsyncResp](
Nan Zhoufe04d492022-06-22 17:10:41 +00002568 const std::shared_ptr<std::set<std::string>>& sensorNames) {
Ed Tanous62598e32023-07-17 17:06:25 -07002569 BMCWEB_LOG_DEBUG("getChassisCb enter");
Ed Tanous002d39b2022-05-31 08:59:27 -07002570 processSensorList(sensorsAsyncResp, sensorNames);
Ed Tanous62598e32023-07-17 17:06:25 -07002571 BMCWEB_LOG_DEBUG("getChassisCb exit");
Ed Tanous002d39b2022-05-31 08:59:27 -07002572 };
Nan Zhou928fefb2022-03-28 08:45:00 -07002573 // SensorCollection doesn't contain the Redundancy property
2574 if (sensorsAsyncResp->chassisSubNode != sensors::node::sensors)
2575 {
2576 sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
2577 nlohmann::json::array();
2578 }
Shawn McCarney26f03892019-05-03 13:20:24 -05002579 // Get set of sensors in chassis
Ed Tanous7f1cc262022-08-09 13:33:57 -07002580 getChassis(sensorsAsyncResp->asyncResp, sensorsAsyncResp->chassisId,
2581 sensorsAsyncResp->chassisSubNode, sensorsAsyncResp->types,
2582 std::move(getChassisCb));
Ed Tanous62598e32023-07-17 17:06:25 -07002583 BMCWEB_LOG_DEBUG("getChassisData exit");
Ed Tanous271584a2019-07-09 16:24:22 -07002584}
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002585
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302586/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002587 * @brief Find the requested sensorName in the list of all sensors supplied by
2588 * the chassis node
2589 *
2590 * @param sensorName The sensor name supplied in the PATCH request
2591 * @param sensorsList The list of sensors managed by the chassis node
2592 * @param sensorsModified The list of sensors that were found as a result of
2593 * repeated calls to this function
2594 */
Nan Zhoufe04d492022-06-22 17:10:41 +00002595inline bool
2596 findSensorNameUsingSensorPath(std::string_view sensorName,
Ed Tanous02cad962022-06-30 16:50:15 -07002597 const std::set<std::string>& sensorsList,
Nan Zhoufe04d492022-06-22 17:10:41 +00002598 std::set<std::string>& sensorsModified)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002599{
Nan Zhoufe04d492022-06-22 17:10:41 +00002600 for (const auto& chassisSensor : sensorsList)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002601 {
George Liu28aa8de2021-02-01 15:13:30 +08002602 sdbusplus::message::object_path path(chassisSensor);
Ed Tanousb00dcc22021-02-23 12:52:50 -08002603 std::string thisSensorName = path.filename();
George Liu28aa8de2021-02-01 15:13:30 +08002604 if (thisSensorName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002605 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002606 continue;
2607 }
2608 if (thisSensorName == sensorName)
2609 {
2610 sensorsModified.emplace(chassisSensor);
2611 return true;
2612 }
2613 }
2614 return false;
2615}
2616
Ed Tanousc71d6122022-11-29 14:10:32 -08002617inline std::pair<std::string, std::string>
2618 splitSensorNameAndType(std::string_view sensorId)
2619{
2620 size_t index = sensorId.find('_');
2621 if (index == std::string::npos)
2622 {
2623 return std::make_pair<std::string, std::string>("", "");
2624 }
2625 std::string sensorType{sensorId.substr(0, index)};
2626 std::string sensorName{sensorId.substr(index + 1)};
2627 // fan_pwm and fan_tach need special handling
2628 if (sensorType == "fantach" || sensorType == "fanpwm")
2629 {
2630 sensorType.insert(3, 1, '_');
2631 }
2632 return std::make_pair(sensorType, sensorName);
2633}
2634
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002635/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302636 * @brief Entry point for overriding sensor values of given sensor
2637 *
zhanghch058d1b46d2021-04-01 11:18:24 +08002638 * @param sensorAsyncResp response object
Carol Wang4bb3dc32019-10-17 18:15:02 +08002639 * @param allCollections Collections extract from sensors' request patch info
jayaprakash Mutyala91e130a2020-03-04 22:26:38 +00002640 * @param chassisSubNode Chassis Node for which the query has to happen
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302641 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002642inline void setSensorsOverride(
Ed Tanousb5a76932020-09-29 16:16:58 -07002643 const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
Ed Tanous08850572024-03-06 15:09:17 -08002644 std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>&
jayaprakash Mutyala397fd612020-02-06 23:33:34 +00002645 allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302646{
Ed Tanous62598e32023-07-17 17:06:25 -07002647 BMCWEB_LOG_INFO("setSensorsOverride for subNode{}",
2648 sensorAsyncResp->chassisSubNode);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302649
Ed Tanousd02aad32024-02-13 14:43:34 -08002650 std::string_view propertyValueName;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302651 std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302652 std::string memberId;
Ed Tanous543f4402022-01-06 13:12:53 -08002653 double value = 0.0;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302654 for (auto& collectionItems : allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302655 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302656 if (collectionItems.first == "Temperatures")
2657 {
2658 propertyValueName = "ReadingCelsius";
2659 }
2660 else if (collectionItems.first == "Fans")
2661 {
2662 propertyValueName = "Reading";
2663 }
2664 else
2665 {
2666 propertyValueName = "ReadingVolts";
2667 }
2668 for (auto& item : collectionItems.second)
2669 {
Ed Tanous08850572024-03-06 15:09:17 -08002670 if (!json_util::readJsonObject(
2671 item, sensorAsyncResp->asyncResp->res, "MemberId", memberId,
2672 propertyValueName, value))
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302673 {
2674 return;
2675 }
2676 overrideMap.emplace(memberId,
2677 std::make_pair(value, collectionItems.first));
2678 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302679 }
Carol Wang4bb3dc32019-10-17 18:15:02 +08002680
Ed Tanous002d39b2022-05-31 08:59:27 -07002681 auto getChassisSensorListCb =
Ed Tanousd02aad32024-02-13 14:43:34 -08002682 [sensorAsyncResp, overrideMap,
2683 propertyValueNameStr = std::string(propertyValueName)](
Nan Zhoufe04d492022-06-22 17:10:41 +00002684 const std::shared_ptr<std::set<std::string>>& sensorsList) {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002685 // Match sensor names in the PATCH request to those managed by the
2686 // chassis node
Nan Zhoufe04d492022-06-22 17:10:41 +00002687 const std::shared_ptr<std::set<std::string>> sensorNames =
2688 std::make_shared<std::set<std::string>>();
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302689 for (const auto& item : overrideMap)
2690 {
2691 const auto& sensor = item.first;
Ed Tanousc71d6122022-11-29 14:10:32 -08002692 std::pair<std::string, std::string> sensorNameType =
2693 splitSensorNameAndType(sensor);
2694 if (!findSensorNameUsingSensorPath(sensorNameType.second,
2695 *sensorsList, *sensorNames))
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302696 {
Ed Tanous62598e32023-07-17 17:06:25 -07002697 BMCWEB_LOG_INFO("Unable to find memberId {}", item.first);
zhanghch058d1b46d2021-04-01 11:18:24 +08002698 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302699 item.second.second, item.first);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302700 return;
2701 }
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302702 }
2703 // Get the connection to which the memberId belongs
Ed Tanous002d39b2022-05-31 08:59:27 -07002704 auto getObjectsWithConnectionCb =
Ed Tanousd02aad32024-02-13 14:43:34 -08002705 [sensorAsyncResp, overrideMap, propertyValueNameStr](
2706 const std::set<std::string>& /*connections*/,
2707 const std::set<std::pair<std::string, std::string>>&
2708 objectsWithConnection) {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002709 if (objectsWithConnection.size() != overrideMap.size())
2710 {
Ed Tanous62598e32023-07-17 17:06:25 -07002711 BMCWEB_LOG_INFO(
2712 "Unable to find all objects with proper connection {} requested {}",
2713 objectsWithConnection.size(), overrideMap.size());
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002714 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
2715 sensorAsyncResp->chassisSubNode ==
2716 sensors::node::thermal
2717 ? "Temperatures"
2718 : "Voltages",
2719 "Count");
2720 return;
2721 }
2722 for (const auto& item : objectsWithConnection)
2723 {
2724 sdbusplus::message::object_path path(item.first);
2725 std::string sensorName = path.filename();
2726 if (sensorName.empty())
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302727 {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002728 messages::internalError(sensorAsyncResp->asyncResp->res);
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302729 return;
2730 }
Ban Feng3f5eb752023-06-29 09:19:20 +08002731 std::string id = path.parent_path().filename();
Ed Tanous3544d2a2023-08-06 18:12:20 -07002732 auto remove = std::ranges::remove(id, '_');
2733 id.erase(std::ranges::begin(remove), id.end());
Ban Feng3f5eb752023-06-29 09:19:20 +08002734 id += "_";
2735 id += sensorName;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302736
Ban Feng3f5eb752023-06-29 09:19:20 +08002737 const auto& iterator = overrideMap.find(id);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002738 if (iterator == overrideMap.end())
2739 {
Ed Tanous62598e32023-07-17 17:06:25 -07002740 BMCWEB_LOG_INFO("Unable to find sensor object{}",
2741 item.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002742 messages::internalError(sensorAsyncResp->asyncResp->res);
2743 return;
2744 }
Ginu Georgee93abac2024-06-14 17:35:27 +05302745 setDbusProperty(sensorAsyncResp->asyncResp,
2746 propertyValueNameStr, item.second, item.first,
2747 "xyz.openbmc_project.Sensor.Value", "Value",
Ed Tanousd02aad32024-02-13 14:43:34 -08002748 iterator->second.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002749 }
2750 };
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302751 // Get object with connection for the given sensor name
2752 getObjectsWithConnection(sensorAsyncResp, sensorNames,
2753 std::move(getObjectsWithConnectionCb));
2754 };
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302755 // get full sensor list for the given chassisId and cross verify the sensor.
Ed Tanous7f1cc262022-08-09 13:33:57 -07002756 getChassis(sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId,
2757 sensorAsyncResp->chassisSubNode, sensorAsyncResp->types,
2758 std::move(getChassisSensorListCb));
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302759}
2760
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002761/**
2762 * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus
2763 * path of the sensor.
2764 *
2765 * Function builds valid Redfish response for sensor query of given chassis and
2766 * node. It then builds metadata about Redfish<->D-Bus correlations and provides
2767 * it to caller in a callback.
2768 *
2769 * @param chassis Chassis for which retrieval should be performed
2770 * @param node Node (group) of sensors. See sensors::node for supported values
2771 * @param mapComplete Callback to be called with retrieval result
2772 */
Ed Tanous931edc72023-11-01 12:09:07 -07002773template <typename Callback>
Krzysztof Grobelny021d32c2021-10-29 16:00:07 +02002774inline void retrieveUriToDbusMap(const std::string& chassis,
2775 const std::string& node,
Ed Tanous931edc72023-11-01 12:09:07 -07002776 Callback&& mapComplete)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002777{
Ed Tanous02da7c52022-02-27 00:09:02 -08002778 decltype(sensors::paths)::const_iterator pathIt =
2779 std::find_if(sensors::paths.cbegin(), sensors::paths.cend(),
2780 [&node](auto&& val) { return val.first == node; });
2781 if (pathIt == sensors::paths.cend())
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002782 {
Ed Tanous62598e32023-07-17 17:06:25 -07002783 BMCWEB_LOG_ERROR("Wrong node provided : {}", node);
Ed Tanous6804b5c2023-10-31 14:50:03 -07002784 std::map<std::string, std::string> noop;
2785 mapComplete(boost::beast::http::status::bad_request, noop);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002786 return;
2787 }
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002788
Nan Zhou72374eb2022-01-27 17:06:51 -08002789 auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
Ed Tanous931edc72023-11-01 12:09:07 -07002790 auto callback = [asyncResp,
Ed Tanous8cb2c022024-03-27 16:31:46 -07002791 mapCompleteCb = std::forward<Callback>(mapComplete)](
Nan Zhoufe04d492022-06-22 17:10:41 +00002792 const boost::beast::http::status status,
2793 const std::map<std::string, std::string>& uriToDbus) {
2794 mapCompleteCb(status, uriToDbus);
2795 };
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002796
2797 auto resp = std::make_shared<SensorsAsyncResp>(
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002798 asyncResp, chassis, pathIt->second, node, std::move(callback));
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002799 getChassisData(resp);
2800}
2801
Nan Zhoubacb2162022-04-06 11:28:32 -07002802namespace sensors
2803{
Nan Zhou928fefb2022-03-28 08:45:00 -07002804
Nan Zhoubacb2162022-04-06 11:28:32 -07002805inline void getChassisCallback(
Ed Tanousc1d019a2022-08-06 09:36:06 -07002806 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2807 std::string_view chassisId, std::string_view chassisSubNode,
Nan Zhoufe04d492022-06-22 17:10:41 +00002808 const std::shared_ptr<std::set<std::string>>& sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002809{
Ed Tanous62598e32023-07-17 17:06:25 -07002810 BMCWEB_LOG_DEBUG("getChassisCallback enter ");
Nan Zhoubacb2162022-04-06 11:28:32 -07002811
Ed Tanousc1d019a2022-08-06 09:36:06 -07002812 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
2813 for (const std::string& sensor : *sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002814 {
Ed Tanous62598e32023-07-17 17:06:25 -07002815 BMCWEB_LOG_DEBUG("Adding sensor: {}", sensor);
Nan Zhoubacb2162022-04-06 11:28:32 -07002816
2817 sdbusplus::message::object_path path(sensor);
2818 std::string sensorName = path.filename();
2819 if (sensorName.empty())
2820 {
Ed Tanous62598e32023-07-17 17:06:25 -07002821 BMCWEB_LOG_ERROR("Invalid sensor path: {}", sensor);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002822 messages::internalError(asyncResp->res);
Nan Zhoubacb2162022-04-06 11:28:32 -07002823 return;
2824 }
Ed Tanousc1d019a2022-08-06 09:36:06 -07002825 std::string type = path.parent_path().filename();
2826 // fan_tach has an underscore in it, so remove it to "normalize" the
2827 // type in the URI
Ed Tanous3544d2a2023-08-06 18:12:20 -07002828 auto remove = std::ranges::remove(type, '_');
2829 type.erase(std::ranges::begin(remove), type.end());
Ed Tanousc1d019a2022-08-06 09:36:06 -07002830
Ed Tanous14766872022-03-15 10:44:42 -07002831 nlohmann::json::object_t member;
Ed Tanousc1d019a2022-08-06 09:36:06 -07002832 std::string id = type;
2833 id += "_";
2834 id += sensorName;
Ed Tanousef4c65b2023-04-24 15:28:50 -07002835 member["@odata.id"] = boost::urls::format(
2836 "/redfish/v1/Chassis/{}/{}/{}", chassisId, chassisSubNode, id);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002837
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002838 entriesArray.emplace_back(std::move(member));
Nan Zhoubacb2162022-04-06 11:28:32 -07002839 }
2840
Ed Tanousc1d019a2022-08-06 09:36:06 -07002841 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Ed Tanous62598e32023-07-17 17:06:25 -07002842 BMCWEB_LOG_DEBUG("getChassisCallback exit");
Nan Zhoubacb2162022-04-06 11:28:32 -07002843}
Nan Zhoue6bd8462022-06-01 04:35:35 +00002844
Ed Tanousac106bf2023-06-07 09:24:59 -07002845inline void handleSensorCollectionGet(
2846 App& app, const crow::Request& req,
2847 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2848 const std::string& chassisId)
Nan Zhoude167a62022-06-01 04:47:45 +00002849{
2850 query_param::QueryCapabilities capabilities = {
2851 .canDelegateExpandLevel = 1,
2852 };
2853 query_param::Query delegatedQuery;
Ed Tanousac106bf2023-06-07 09:24:59 -07002854 if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
Nan Zhoude167a62022-06-01 04:47:45 +00002855 delegatedQuery, capabilities))
2856 {
2857 return;
2858 }
2859
2860 if (delegatedQuery.expandType != query_param::ExpandType::None)
2861 {
2862 // we perform efficient expand.
Ed Tanousac106bf2023-06-07 09:24:59 -07002863 auto sensorsAsyncResp = std::make_shared<SensorsAsyncResp>(
2864 asyncResp, chassisId, sensors::dbus::sensorPaths,
Nan Zhoude167a62022-06-01 04:47:45 +00002865 sensors::node::sensors,
2866 /*efficientExpand=*/true);
Ed Tanousac106bf2023-06-07 09:24:59 -07002867 getChassisData(sensorsAsyncResp);
Nan Zhoude167a62022-06-01 04:47:45 +00002868
Ed Tanous62598e32023-07-17 17:06:25 -07002869 BMCWEB_LOG_DEBUG(
2870 "SensorCollection doGet exit via efficient expand handler");
Nan Zhoude167a62022-06-01 04:47:45 +00002871 return;
Ed Tanous0bad3202022-06-02 13:53:59 -07002872 }
Nan Zhoude167a62022-06-01 04:47:45 +00002873
Nan Zhoude167a62022-06-01 04:47:45 +00002874 // We get all sensors as hyperlinkes in the chassis (this
2875 // implies we reply on the default query parameters handler)
Ed Tanousac106bf2023-06-07 09:24:59 -07002876 getChassis(asyncResp, chassisId, sensors::node::sensors, dbus::sensorPaths,
2877 std::bind_front(sensors::getChassisCallback, asyncResp,
2878 chassisId, sensors::node::sensors));
Ed Tanousc1d019a2022-08-06 09:36:06 -07002879}
Ed Tanous7f1cc262022-08-09 13:33:57 -07002880
Ed Tanousc1d019a2022-08-06 09:36:06 -07002881inline void
2882 getSensorFromDbus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2883 const std::string& sensorPath,
2884 const ::dbus::utility::MapperGetObject& mapperResponse)
2885{
2886 if (mapperResponse.size() != 1)
2887 {
2888 messages::internalError(asyncResp->res);
2889 return;
2890 }
2891 const auto& valueIface = *mapperResponse.begin();
2892 const std::string& connectionName = valueIface.first;
Ed Tanous62598e32023-07-17 17:06:25 -07002893 BMCWEB_LOG_DEBUG("Looking up {}", connectionName);
2894 BMCWEB_LOG_DEBUG("Path {}", sensorPath);
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +02002895
2896 sdbusplus::asio::getAllProperties(
2897 *crow::connections::systemBus, connectionName, sensorPath, "",
Ed Tanousc1d019a2022-08-06 09:36:06 -07002898 [asyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002899 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002900 const ::dbus::utility::DBusPropertiesMap& valuesDict) {
2901 if (ec)
2902 {
2903 messages::internalError(asyncResp->res);
2904 return;
2905 }
2906 sdbusplus::message::object_path path(sensorPath);
2907 std::string name = path.filename();
2908 path = path.parent_path();
2909 std::string type = path.filename();
2910 objectPropertiesToJson(name, type, sensors::node::sensors, valuesDict,
2911 asyncResp->res.jsonValue, nullptr);
Patrick Williams5a39f772023-10-20 11:20:21 -05002912 });
Nan Zhoude167a62022-06-01 04:47:45 +00002913}
2914
Nan Zhoue6bd8462022-06-01 04:35:35 +00002915inline void handleSensorGet(App& app, const crow::Request& req,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002916 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous677bb752022-09-15 10:52:19 -07002917 const std::string& chassisId,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002918 const std::string& sensorId)
Nan Zhoue6bd8462022-06-01 04:35:35 +00002919{
Ed Tanousc1d019a2022-08-06 09:36:06 -07002920 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Nan Zhoue6bd8462022-06-01 04:35:35 +00002921 {
2922 return;
2923 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002924 std::pair<std::string, std::string> nameType =
2925 splitSensorNameAndType(sensorId);
2926 if (nameType.first.empty() || nameType.second.empty())
Ed Tanousc1d019a2022-08-06 09:36:06 -07002927 {
2928 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2929 return;
2930 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002931
Ed Tanousef4c65b2023-04-24 15:28:50 -07002932 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2933 "/redfish/v1/Chassis/{}/Sensors/{}", chassisId, sensorId);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002934
Ed Tanous62598e32023-07-17 17:06:25 -07002935 BMCWEB_LOG_DEBUG("Sensor doGet enter");
Nan Zhoue6bd8462022-06-01 04:35:35 +00002936
George Liu2b731192023-01-11 16:27:13 +08002937 constexpr std::array<std::string_view, 1> interfaces = {
Nan Zhoue6bd8462022-06-01 04:35:35 +00002938 "xyz.openbmc_project.Sensor.Value"};
Ed Tanousc71d6122022-11-29 14:10:32 -08002939 std::string sensorPath = "/xyz/openbmc_project/sensors/" + nameType.first +
2940 '/' + nameType.second;
Nan Zhoue6bd8462022-06-01 04:35:35 +00002941 // Get a list of all of the sensors that implement Sensor.Value
2942 // and get the path and service name associated with the sensor
George Liu2b731192023-01-11 16:27:13 +08002943 ::dbus::utility::getDbusObject(
2944 sensorPath, interfaces,
Myung Baeaec0ec32023-05-31 15:10:01 -05002945 [asyncResp, sensorId,
George Liu2b731192023-01-11 16:27:13 +08002946 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002947 const ::dbus::utility::MapperGetObject& subtree) {
Ed Tanous62598e32023-07-17 17:06:25 -07002948 BMCWEB_LOG_DEBUG("respHandler1 enter");
Myung Baeaec0ec32023-05-31 15:10:01 -05002949 if (ec == boost::system::errc::io_error)
2950 {
Ed Tanous62598e32023-07-17 17:06:25 -07002951 BMCWEB_LOG_WARNING("Sensor not found from getSensorPaths");
Myung Baeaec0ec32023-05-31 15:10:01 -05002952 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2953 return;
2954 }
Nan Zhoue6bd8462022-06-01 04:35:35 +00002955 if (ec)
2956 {
Ed Tanousc1d019a2022-08-06 09:36:06 -07002957 messages::internalError(asyncResp->res);
Ed Tanous62598e32023-07-17 17:06:25 -07002958 BMCWEB_LOG_ERROR(
2959 "Sensor getSensorPaths resp_handler: Dbus error {}", ec);
Nan Zhoue6bd8462022-06-01 04:35:35 +00002960 return;
2961 }
Ed Tanousc1d019a2022-08-06 09:36:06 -07002962 getSensorFromDbus(asyncResp, sensorPath, subtree);
Ed Tanous62598e32023-07-17 17:06:25 -07002963 BMCWEB_LOG_DEBUG("respHandler1 exit");
Patrick Williams5a39f772023-10-20 11:20:21 -05002964 });
Nan Zhoue6bd8462022-06-01 04:35:35 +00002965}
2966
Nan Zhoubacb2162022-04-06 11:28:32 -07002967} // namespace sensors
2968
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002969inline void requestRoutesSensorCollection(App& app)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002970{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002971 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
Ed Tanoused398212021-06-09 17:05:54 -07002972 .privileges(redfish::privileges::getSensorCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002973 .methods(boost::beast::http::verb::get)(
Nan Zhoude167a62022-06-01 04:47:45 +00002974 std::bind_front(sensors::handleSensorCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002975}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002976
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002977inline void requestRoutesSensor(App& app)
2978{
2979 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002980 .privileges(redfish::privileges::getSensor)
Ed Tanous002d39b2022-05-31 08:59:27 -07002981 .methods(boost::beast::http::verb::get)(
Nan Zhoue6bd8462022-06-01 04:35:35 +00002982 std::bind_front(sensors::handleSensorGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002983}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002984
Ed Tanous1abe55e2018-09-05 08:30:59 -07002985} // namespace redfish