xref: /openbmc/dbus-sensors/src/psu/PSUEvent.cpp (revision 4155a5a83b292a8b29daedb9577090e053383e98)
1d7be555eSGeorge Liu /*
2d7be555eSGeorge Liu // Copyright (c) 2019 Intel Corporation
3d7be555eSGeorge Liu //
4d7be555eSGeorge Liu // Licensed under the Apache License, Version 2.0 (the "License");
5d7be555eSGeorge Liu // you may not use this file except in compliance with the License.
6d7be555eSGeorge Liu // You may obtain a copy of the License at
7d7be555eSGeorge Liu //
8d7be555eSGeorge Liu //      http://www.apache.org/licenses/LICENSE-2.0
9d7be555eSGeorge Liu //
10d7be555eSGeorge Liu // Unless required by applicable law or agreed to in writing, software
11d7be555eSGeorge Liu // distributed under the License is distributed on an "AS IS" BASIS,
12d7be555eSGeorge Liu // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d7be555eSGeorge Liu // See the License for the specific language governing permissions and
14d7be555eSGeorge Liu // limitations under the License.
15d7be555eSGeorge Liu */
16d7be555eSGeorge Liu 
17d7be555eSGeorge Liu #include "PSUEvent.hpp"
18d7be555eSGeorge Liu 
19d7be555eSGeorge Liu #include "SensorPaths.hpp"
20d7be555eSGeorge Liu #include "Utils.hpp"
21d7be555eSGeorge Liu 
22d7be555eSGeorge Liu #include <boost/asio/buffer.hpp>
23d7be555eSGeorge Liu #include <boost/asio/error.hpp>
24d7be555eSGeorge Liu #include <boost/asio/io_context.hpp>
25d7be555eSGeorge Liu #include <boost/asio/random_access_file.hpp>
26d7be555eSGeorge Liu #include <boost/container/flat_map.hpp>
27d7be555eSGeorge Liu #include <phosphor-logging/lg2.hpp>
28d7be555eSGeorge Liu #include <sdbusplus/asio/connection.hpp>
29d7be555eSGeorge Liu #include <sdbusplus/asio/object_server.hpp>
30d7be555eSGeorge Liu 
31d7be555eSGeorge Liu #include <array>
32d7be555eSGeorge Liu #include <chrono>
33d7be555eSGeorge Liu #include <cstddef>
34d7be555eSGeorge Liu #include <memory>
35d7be555eSGeorge Liu #include <set>
36d7be555eSGeorge Liu #include <stdexcept>
37d7be555eSGeorge Liu #include <string>
38d7be555eSGeorge Liu #include <utility>
39d7be555eSGeorge Liu #include <vector>
40d7be555eSGeorge Liu 
PSUCombineEvent(sdbusplus::asio::object_server & objectServer,std::shared_ptr<sdbusplus::asio::connection> & conn,boost::asio::io_context & io,const std::string & psuName,const PowerState & powerState,EventPathList & eventPathList,GroupEventPathList & groupEventPathList,const std::string & combineEventName,double pollRate)41d7be555eSGeorge Liu PSUCombineEvent::PSUCombineEvent(
42d7be555eSGeorge Liu     sdbusplus::asio::object_server& objectServer,
43d7be555eSGeorge Liu     std::shared_ptr<sdbusplus::asio::connection>& conn,
44d7be555eSGeorge Liu     boost::asio::io_context& io, const std::string& psuName,
45d7be555eSGeorge Liu     const PowerState& powerState, EventPathList& eventPathList,
46d7be555eSGeorge Liu     GroupEventPathList& groupEventPathList, const std::string& combineEventName,
47d7be555eSGeorge Liu     double pollRate) : objServer(objectServer)
48d7be555eSGeorge Liu {
49d7be555eSGeorge Liu     std::string psuNameEscaped = sensor_paths::escapePathForDbus(psuName);
50d7be555eSGeorge Liu     eventInterface = objServer.add_interface(
51d7be555eSGeorge Liu         "/xyz/openbmc_project/State/Decorator/" + psuNameEscaped + "_" +
52d7be555eSGeorge Liu             combineEventName,
53d7be555eSGeorge Liu         "xyz.openbmc_project.State.Decorator.OperationalStatus");
54d7be555eSGeorge Liu     eventInterface->register_property("functional", true);
55d7be555eSGeorge Liu 
56d7be555eSGeorge Liu     if (!eventInterface->initialize())
57d7be555eSGeorge Liu     {
58*4155a5a8SGeorge Liu         lg2::error("error initializing event interface");
59d7be555eSGeorge Liu     }
60d7be555eSGeorge Liu 
61d7be555eSGeorge Liu     std::shared_ptr<std::set<std::string>> combineEvent =
62d7be555eSGeorge Liu         std::make_shared<std::set<std::string>>();
63d7be555eSGeorge Liu     for (const auto& [eventName, paths] : eventPathList)
64d7be555eSGeorge Liu     {
65d7be555eSGeorge Liu         std::shared_ptr<std::set<std::string>> assert =
66d7be555eSGeorge Liu             std::make_shared<std::set<std::string>>();
67d7be555eSGeorge Liu         std::shared_ptr<bool> state = std::make_shared<bool>(false);
68d7be555eSGeorge Liu 
69d7be555eSGeorge Liu         std::string eventPSUName = eventName + psuName;
70d7be555eSGeorge Liu         for (const auto& path : paths)
71d7be555eSGeorge Liu         {
72d7be555eSGeorge Liu             auto p = std::make_shared<PSUSubEvent>(
73d7be555eSGeorge Liu                 eventInterface, path, conn, io, powerState, eventName,
74d7be555eSGeorge Liu                 eventName, assert, combineEvent, state, psuName, pollRate);
75d7be555eSGeorge Liu             p->setupRead();
76d7be555eSGeorge Liu 
77d7be555eSGeorge Liu             events[eventPSUName].emplace_back(p);
78d7be555eSGeorge Liu             asserts.emplace_back(assert);
79d7be555eSGeorge Liu             states.emplace_back(state);
80d7be555eSGeorge Liu         }
81d7be555eSGeorge Liu     }
82d7be555eSGeorge Liu 
83d7be555eSGeorge Liu     for (const auto& [eventName, groupEvents] : groupEventPathList)
84d7be555eSGeorge Liu     {
85d7be555eSGeorge Liu         for (const auto& [groupEventName, paths] : groupEvents)
86d7be555eSGeorge Liu         {
87d7be555eSGeorge Liu             std::shared_ptr<std::set<std::string>> assert =
88d7be555eSGeorge Liu                 std::make_shared<std::set<std::string>>();
89d7be555eSGeorge Liu             std::shared_ptr<bool> state = std::make_shared<bool>(false);
90d7be555eSGeorge Liu 
91d7be555eSGeorge Liu             std::string eventPSUName = groupEventName + psuName;
92d7be555eSGeorge Liu             for (const auto& path : paths)
93d7be555eSGeorge Liu             {
94d7be555eSGeorge Liu                 auto p = std::make_shared<PSUSubEvent>(
95d7be555eSGeorge Liu                     eventInterface, path, conn, io, powerState, groupEventName,
96d7be555eSGeorge Liu                     eventName, assert, combineEvent, state, psuName, pollRate);
97d7be555eSGeorge Liu                 p->setupRead();
98d7be555eSGeorge Liu                 events[eventPSUName].emplace_back(p);
99d7be555eSGeorge Liu 
100d7be555eSGeorge Liu                 asserts.emplace_back(assert);
101d7be555eSGeorge Liu                 states.emplace_back(state);
102d7be555eSGeorge Liu             }
103d7be555eSGeorge Liu         }
104d7be555eSGeorge Liu     }
105d7be555eSGeorge Liu }
106d7be555eSGeorge Liu 
~PSUCombineEvent()107d7be555eSGeorge Liu PSUCombineEvent::~PSUCombineEvent()
108d7be555eSGeorge Liu {
109d7be555eSGeorge Liu     // Clear unique_ptr first
110d7be555eSGeorge Liu     for (auto& [psuName, subEvents] : events)
111d7be555eSGeorge Liu     {
112d7be555eSGeorge Liu         for (auto& subEventPtr : subEvents)
113d7be555eSGeorge Liu         {
114d7be555eSGeorge Liu             subEventPtr.reset();
115d7be555eSGeorge Liu         }
116d7be555eSGeorge Liu     }
117d7be555eSGeorge Liu     events.clear();
118d7be555eSGeorge Liu     objServer.remove_interface(eventInterface);
119d7be555eSGeorge Liu }
120d7be555eSGeorge Liu 
121d7be555eSGeorge Liu static boost::container::flat_map<std::string,
122d7be555eSGeorge Liu                                   std::pair<std::string, std::string>>
123d7be555eSGeorge Liu     logID = {
124d7be555eSGeorge Liu         {"PredictiveFailure",
125d7be555eSGeorge Liu          {"OpenBMC.0.1.PowerSupplyFailurePredicted",
126d7be555eSGeorge Liu           "OpenBMC.0.1.PowerSupplyPredictedFailureRecovered"}},
127d7be555eSGeorge Liu         {"Failure",
128d7be555eSGeorge Liu          {"OpenBMC.0.1.PowerSupplyFailed", "OpenBMC.0.1.PowerSupplyRecovered"}},
129d7be555eSGeorge Liu         {"ACLost",
130d7be555eSGeorge Liu          {"OpenBMC.0.1.PowerSupplyPowerLost",
131d7be555eSGeorge Liu           "OpenBMC.0.1.PowerSupplyPowerRestored"}},
132d7be555eSGeorge Liu         {"FanFault",
133d7be555eSGeorge Liu          {"OpenBMC.0.1.PowerSupplyFanFailed",
134d7be555eSGeorge Liu           "OpenBMC.0.1.PowerSupplyFanRecovered"}},
135d7be555eSGeorge Liu         {"ConfigureError",
136d7be555eSGeorge Liu          {"OpenBMC.0.1.PowerSupplyConfigurationError",
137d7be555eSGeorge Liu           "OpenBMC.0.1.PowerSupplyConfigurationErrorRecovered"}}};
138d7be555eSGeorge Liu 
PSUSubEvent(std::shared_ptr<sdbusplus::asio::dbus_interface> eventInterface,const std::string & path,std::shared_ptr<sdbusplus::asio::connection> & conn,boost::asio::io_context & io,const PowerState & powerState,const std::string & groupEventName,const std::string & eventName,std::shared_ptr<std::set<std::string>> asserts,std::shared_ptr<std::set<std::string>> combineEvent,std::shared_ptr<bool> state,const std::string & psuName,double pollRate)139d7be555eSGeorge Liu PSUSubEvent::PSUSubEvent(
140d7be555eSGeorge Liu     std::shared_ptr<sdbusplus::asio::dbus_interface> eventInterface,
141d7be555eSGeorge Liu     const std::string& path, std::shared_ptr<sdbusplus::asio::connection>& conn,
142d7be555eSGeorge Liu     boost::asio::io_context& io, const PowerState& powerState,
143d7be555eSGeorge Liu     const std::string& groupEventName, const std::string& eventName,
144d7be555eSGeorge Liu     std::shared_ptr<std::set<std::string>> asserts,
145d7be555eSGeorge Liu     std::shared_ptr<std::set<std::string>> combineEvent,
146d7be555eSGeorge Liu     std::shared_ptr<bool> state, const std::string& psuName, double pollRate) :
147d7be555eSGeorge Liu     eventInterface(std::move(eventInterface)), asserts(std::move(asserts)),
148d7be555eSGeorge Liu     combineEvent(std::move(combineEvent)), assertState(std::move(state)),
149d7be555eSGeorge Liu     path(path), eventName(eventName), readState(powerState), waitTimer(io),
150d7be555eSGeorge Liu 
151d7be555eSGeorge Liu     inputDev(io, path, boost::asio::random_access_file::read_only),
152d7be555eSGeorge Liu     psuName(psuName), groupEventName(groupEventName), systemBus(conn)
153d7be555eSGeorge Liu {
154d7be555eSGeorge Liu     buffer = std::make_shared<std::array<char, 128>>();
155d7be555eSGeorge Liu     if (pollRate > 0.0)
156d7be555eSGeorge Liu     {
157d7be555eSGeorge Liu         eventPollMs = static_cast<unsigned int>(pollRate * 1000);
158d7be555eSGeorge Liu     }
159d7be555eSGeorge Liu 
160d7be555eSGeorge Liu     auto found = logID.find(eventName);
161d7be555eSGeorge Liu     if (found == logID.end())
162d7be555eSGeorge Liu     {
163d7be555eSGeorge Liu         assertMessage.clear();
164d7be555eSGeorge Liu         deassertMessage.clear();
165d7be555eSGeorge Liu     }
166d7be555eSGeorge Liu     else
167d7be555eSGeorge Liu     {
168d7be555eSGeorge Liu         assertMessage = found->second.first;
169d7be555eSGeorge Liu         deassertMessage = found->second.second;
170d7be555eSGeorge Liu     }
171d7be555eSGeorge Liu 
172d7be555eSGeorge Liu     auto fanPos = path.find("fan");
173d7be555eSGeorge Liu     if (fanPos != std::string::npos)
174d7be555eSGeorge Liu     {
175d7be555eSGeorge Liu         fanName = path.substr(fanPos);
176d7be555eSGeorge Liu         auto fanNamePos = fanName.find('_');
177d7be555eSGeorge Liu         if (fanNamePos != std::string::npos)
178d7be555eSGeorge Liu         {
179d7be555eSGeorge Liu             fanName = fanName.substr(0, fanNamePos);
180d7be555eSGeorge Liu         }
181d7be555eSGeorge Liu     }
182d7be555eSGeorge Liu }
183d7be555eSGeorge Liu 
~PSUSubEvent()184d7be555eSGeorge Liu PSUSubEvent::~PSUSubEvent()
185d7be555eSGeorge Liu {
186d7be555eSGeorge Liu     waitTimer.cancel();
187d7be555eSGeorge Liu     inputDev.close();
188d7be555eSGeorge Liu }
189d7be555eSGeorge Liu 
setupRead()190d7be555eSGeorge Liu void PSUSubEvent::setupRead()
191d7be555eSGeorge Liu {
192d7be555eSGeorge Liu     if (!readingStateGood(readState))
193d7be555eSGeorge Liu     {
194d7be555eSGeorge Liu         // Deassert the event
195d7be555eSGeorge Liu         updateValue(0);
196d7be555eSGeorge Liu         restartRead();
197d7be555eSGeorge Liu         return;
198d7be555eSGeorge Liu     }
199d7be555eSGeorge Liu     if (!buffer)
200d7be555eSGeorge Liu     {
201*4155a5a8SGeorge Liu         lg2::error("Buffer was invalid?");
202d7be555eSGeorge Liu         return;
203d7be555eSGeorge Liu     }
204d7be555eSGeorge Liu 
205d7be555eSGeorge Liu     std::weak_ptr<PSUSubEvent> weakRef = weak_from_this();
206d7be555eSGeorge Liu     inputDev.async_read_some_at(
207d7be555eSGeorge Liu         0, boost::asio::buffer(buffer->data(), buffer->size() - 1),
208d7be555eSGeorge Liu         [weakRef, buffer{buffer}](const boost::system::error_code& ec,
209d7be555eSGeorge Liu                                   std::size_t bytesTransferred) {
210d7be555eSGeorge Liu             std::shared_ptr<PSUSubEvent> self = weakRef.lock();
211d7be555eSGeorge Liu             if (self)
212d7be555eSGeorge Liu             {
213d7be555eSGeorge Liu                 self->handleResponse(ec, bytesTransferred);
214d7be555eSGeorge Liu             }
215d7be555eSGeorge Liu         });
216d7be555eSGeorge Liu }
217d7be555eSGeorge Liu 
restartRead()218d7be555eSGeorge Liu void PSUSubEvent::restartRead()
219d7be555eSGeorge Liu {
220d7be555eSGeorge Liu     std::weak_ptr<PSUSubEvent> weakRef = weak_from_this();
221d7be555eSGeorge Liu     waitTimer.expires_after(std::chrono::milliseconds(eventPollMs));
222d7be555eSGeorge Liu     waitTimer.async_wait([weakRef](const boost::system::error_code& ec) {
223d7be555eSGeorge Liu         if (ec == boost::asio::error::operation_aborted)
224d7be555eSGeorge Liu         {
225d7be555eSGeorge Liu             return;
226d7be555eSGeorge Liu         }
227d7be555eSGeorge Liu         std::shared_ptr<PSUSubEvent> self = weakRef.lock();
228d7be555eSGeorge Liu         if (self)
229d7be555eSGeorge Liu         {
230d7be555eSGeorge Liu             self->setupRead();
231d7be555eSGeorge Liu         }
232d7be555eSGeorge Liu     });
233d7be555eSGeorge Liu }
234d7be555eSGeorge Liu 
handleResponse(const boost::system::error_code & err,size_t bytesTransferred)235d7be555eSGeorge Liu void PSUSubEvent::handleResponse(const boost::system::error_code& err,
236d7be555eSGeorge Liu                                  size_t bytesTransferred)
237d7be555eSGeorge Liu {
238d7be555eSGeorge Liu     if (err == boost::asio::error::operation_aborted)
239d7be555eSGeorge Liu     {
240d7be555eSGeorge Liu         return;
241d7be555eSGeorge Liu     }
242d7be555eSGeorge Liu 
243d7be555eSGeorge Liu     if ((err == boost::system::errc::bad_file_descriptor) ||
244d7be555eSGeorge Liu         (err == boost::asio::error::misc_errors::not_found))
245d7be555eSGeorge Liu     {
246d7be555eSGeorge Liu         return;
247d7be555eSGeorge Liu     }
248d7be555eSGeorge Liu     if (!buffer)
249d7be555eSGeorge Liu     {
250*4155a5a8SGeorge Liu         lg2::error("Buffer was invalid?");
251d7be555eSGeorge Liu         return;
252d7be555eSGeorge Liu     }
253d7be555eSGeorge Liu     // null terminate the string so we don't walk off the end
254d7be555eSGeorge Liu     std::array<char, 128>& bufferRef = *buffer;
255d7be555eSGeorge Liu     bufferRef[bytesTransferred] = '\0';
256d7be555eSGeorge Liu 
257d7be555eSGeorge Liu     if (!err)
258d7be555eSGeorge Liu     {
259d7be555eSGeorge Liu         try
260d7be555eSGeorge Liu         {
261d7be555eSGeorge Liu             int nvalue = std::stoi(bufferRef.data());
262d7be555eSGeorge Liu             updateValue(nvalue);
263d7be555eSGeorge Liu             errCount = 0;
264d7be555eSGeorge Liu         }
265d7be555eSGeorge Liu         catch (const std::invalid_argument&)
266d7be555eSGeorge Liu         {
267d7be555eSGeorge Liu             errCount++;
268d7be555eSGeorge Liu         }
269d7be555eSGeorge Liu     }
270d7be555eSGeorge Liu     else
271d7be555eSGeorge Liu     {
272d7be555eSGeorge Liu         errCount++;
273d7be555eSGeorge Liu     }
274d7be555eSGeorge Liu     if (errCount >= warnAfterErrorCount)
275d7be555eSGeorge Liu     {
276d7be555eSGeorge Liu         if (errCount == warnAfterErrorCount)
277d7be555eSGeorge Liu         {
278*4155a5a8SGeorge Liu             lg2::error("Failure to read event at '{PATH}'", "PATH", path);
279d7be555eSGeorge Liu         }
280d7be555eSGeorge Liu         updateValue(0);
281d7be555eSGeorge Liu         errCount++;
282d7be555eSGeorge Liu     }
283d7be555eSGeorge Liu     restartRead();
284d7be555eSGeorge Liu }
285d7be555eSGeorge Liu 
286d7be555eSGeorge Liu // Any of the sub events of one event is asserted, then the event will be
287d7be555eSGeorge Liu // asserted. Only if none of the sub events are asserted, the event will be
288d7be555eSGeorge Liu // deasserted.
updateValue(const int & newValue)289d7be555eSGeorge Liu void PSUSubEvent::updateValue(const int& newValue)
290d7be555eSGeorge Liu {
291d7be555eSGeorge Liu     // Take no action if value already equal
292d7be555eSGeorge Liu     // Same semantics as Sensor::updateValue(const double&)
293d7be555eSGeorge Liu     if (newValue == value)
294d7be555eSGeorge Liu     {
295d7be555eSGeorge Liu         return;
296d7be555eSGeorge Liu     }
297d7be555eSGeorge Liu 
298d7be555eSGeorge Liu     if (newValue == 0)
299d7be555eSGeorge Liu     {
300d7be555eSGeorge Liu         // log deassert only after all asserts are gone
301d7be555eSGeorge Liu         if (!(*asserts).empty())
302d7be555eSGeorge Liu         {
303d7be555eSGeorge Liu             auto found = (*asserts).find(path);
304d7be555eSGeorge Liu             if (found == (*asserts).end())
305d7be555eSGeorge Liu             {
306d7be555eSGeorge Liu                 return;
307d7be555eSGeorge Liu             }
308d7be555eSGeorge Liu             (*asserts).erase(path);
309d7be555eSGeorge Liu 
310d7be555eSGeorge Liu             return;
311d7be555eSGeorge Liu         }
312d7be555eSGeorge Liu         if (*assertState)
313d7be555eSGeorge Liu         {
314d7be555eSGeorge Liu             *assertState = false;
315d7be555eSGeorge Liu             auto foundCombine = (*combineEvent).find(groupEventName);
316d7be555eSGeorge Liu             if (foundCombine == (*combineEvent).end())
317d7be555eSGeorge Liu             {
318d7be555eSGeorge Liu                 return;
319d7be555eSGeorge Liu             }
320d7be555eSGeorge Liu             (*combineEvent).erase(groupEventName);
321d7be555eSGeorge Liu             if (!deassertMessage.empty())
322d7be555eSGeorge Liu             {
323d7be555eSGeorge Liu                 // Fan Failed has two args
324d7be555eSGeorge Liu                 if (deassertMessage == "OpenBMC.0.1.PowerSupplyFanRecovered")
325d7be555eSGeorge Liu                 {
326*4155a5a8SGeorge Liu                     lg2::info("'{EVENT}' deassert", "EVENT", eventName,
327d7be555eSGeorge Liu                               "REDFISH_MESSAGE_ID", deassertMessage,
328d7be555eSGeorge Liu                               "REDFISH_MESSAGE_ARGS",
329d7be555eSGeorge Liu                               (psuName + ',' + fanName));
330d7be555eSGeorge Liu                 }
331d7be555eSGeorge Liu                 else
332d7be555eSGeorge Liu                 {
333*4155a5a8SGeorge Liu                     lg2::info("'{EVENT}' deassert", "EVENT", eventName,
334d7be555eSGeorge Liu                               "REDFISH_MESSAGE_ID", deassertMessage,
335d7be555eSGeorge Liu                               "REDFISH_MESSAGE_ARGS", psuName);
336d7be555eSGeorge Liu                 }
337d7be555eSGeorge Liu             }
338d7be555eSGeorge Liu 
339d7be555eSGeorge Liu             if ((*combineEvent).empty())
340d7be555eSGeorge Liu             {
341d7be555eSGeorge Liu                 eventInterface->set_property("functional", true);
342d7be555eSGeorge Liu             }
343d7be555eSGeorge Liu         }
344d7be555eSGeorge Liu     }
345d7be555eSGeorge Liu     else
346d7be555eSGeorge Liu     {
347*4155a5a8SGeorge Liu         lg2::error("PSUSubEvent asserted by '{PATH}'", "PATH", path);
348d7be555eSGeorge Liu 
349d7be555eSGeorge Liu         if ((!*assertState) && ((*asserts).empty()))
350d7be555eSGeorge Liu         {
351d7be555eSGeorge Liu             *assertState = true;
352d7be555eSGeorge Liu             if (!assertMessage.empty())
353d7be555eSGeorge Liu             {
354d7be555eSGeorge Liu                 // Fan Failed has two args
355d7be555eSGeorge Liu                 if (assertMessage == "OpenBMC.0.1.PowerSupplyFanFailed")
356d7be555eSGeorge Liu                 {
357*4155a5a8SGeorge Liu                     lg2::warning("'{EVENT}' assert", "EVENT", eventName,
358d7be555eSGeorge Liu                                  "REDFISH_MESSAGE_ID", assertMessage,
359d7be555eSGeorge Liu                                  "REDFISH_MESSAGE_ARGS",
360d7be555eSGeorge Liu                                  (psuName + ',' + fanName));
361d7be555eSGeorge Liu                 }
362d7be555eSGeorge Liu                 else
363d7be555eSGeorge Liu                 {
364*4155a5a8SGeorge Liu                     lg2::warning("'{EVENT}' assert", "EVENT", eventName,
365d7be555eSGeorge Liu                                  "REDFISH_MESSAGE_ID", assertMessage,
366d7be555eSGeorge Liu                                  "REDFISH_MESSAGE_ARGS", psuName);
367d7be555eSGeorge Liu                 }
368d7be555eSGeorge Liu             }
369d7be555eSGeorge Liu             if ((*combineEvent).empty())
370d7be555eSGeorge Liu             {
371d7be555eSGeorge Liu                 eventInterface->set_property("functional", false);
372d7be555eSGeorge Liu             }
373d7be555eSGeorge Liu             (*combineEvent).emplace(groupEventName);
374d7be555eSGeorge Liu         }
375d7be555eSGeorge Liu         (*asserts).emplace(path);
376d7be555eSGeorge Liu     }
377d7be555eSGeorge Liu     value = newValue;
378d7be555eSGeorge Liu }
379