blob: f4e59eeb4528e435904db792233f9d17782b79bd [file] [log] [blame]
James Feistbc896df2018-11-26 16:28:17 -08001/*
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
17#include "ExitAirTempSensor.hpp"
18
19#include "Utils.hpp"
20#include "VariantVisitors.hpp"
21
22#include <math.h>
23
24#include <boost/algorithm/string/predicate.hpp>
25#include <boost/algorithm/string/replace.hpp>
26#include <chrono>
27#include <iostream>
28#include <limits>
29#include <numeric>
30#include <sdbusplus/asio/connection.hpp>
31#include <sdbusplus/asio/object_server.hpp>
32#include <vector>
33
34constexpr const float altitudeFactor = 1.14;
35constexpr const char* exitAirIface =
36 "xyz.openbmc_project.Configuration.ExitAirTempSensor";
37constexpr const char* cfmIface = "xyz.openbmc_project.Configuration.CFMSensor";
38
39// todo: this *might* need to be configurable
40constexpr const char* inletTemperatureSensor = "temperature/Front_Panel_Temp";
James Feistbc896df2018-11-26 16:28:17 -080041
42static constexpr bool DEBUG = false;
43
James Feistb2eb3f52018-12-04 16:17:50 -080044static constexpr double cfmMaxReading = 255;
45static constexpr double cfmMinReading = 0;
46
47static void setupSensorMatch(
48 std::vector<sdbusplus::bus::match::match>& matches,
49 sdbusplus::bus::bus& connection, const std::string& type,
50 std::function<void(const double&, sdbusplus::message::message&)>&& callback)
51{
52
53 std::function<void(sdbusplus::message::message & message)> eventHandler =
54 [callback{std::move(callback)}](sdbusplus::message::message& message) {
55 std::string objectName;
James Feist3eb82622019-02-08 13:10:22 -080056 boost::container::flat_map<std::string,
57 std::variant<double, int64_t>>
James Feistb2eb3f52018-12-04 16:17:50 -080058 values;
59 message.read(objectName, values);
60 auto findValue = values.find("Value");
61 if (findValue == values.end())
62 {
63 return;
64 }
James Feist3eb82622019-02-08 13:10:22 -080065 double value =
66 std::visit(VariantToDoubleVisitor(), findValue->second);
James Feist9566bfa2019-01-29 15:31:23 -080067 if (std::isnan(value))
68 {
69 return;
70 }
71
James Feistb2eb3f52018-12-04 16:17:50 -080072 callback(value, message);
73 };
74 matches.emplace_back(connection,
75 "type='signal',"
76 "member='PropertiesChanged',interface='org."
77 "freedesktop.DBus.Properties',path_"
78 "namespace='/xyz/openbmc_project/sensors/" +
79 std::string(type) +
80 "',arg0='xyz.openbmc_project.Sensor.Value'",
81 std::move(eventHandler));
82}
83
James Feistb2eb3f52018-12-04 16:17:50 -080084CFMSensor::CFMSensor(std::shared_ptr<sdbusplus::asio::connection>& conn,
85 const std::string& sensorName,
86 const std::string& sensorConfiguration,
87 sdbusplus::asio::object_server& objectServer,
88 std::vector<thresholds::Threshold>&& thresholds,
89 std::shared_ptr<ExitAirTempSensor>& parent) :
90 Sensor(boost::replace_all_copy(sensorName, " ", "_"),
91 "" /* todo: remove arg from base*/, std::move(thresholds),
92 sensorConfiguration, "xyz.openbmc_project.Configuration.ExitAirTemp",
93 cfmMaxReading, cfmMinReading),
James Feist9566bfa2019-01-29 15:31:23 -080094 dbusConnection(conn), parent(parent), objServer(objectServer)
James Feistb2eb3f52018-12-04 16:17:50 -080095{
96 sensorInterface =
97 objectServer.add_interface("/xyz/openbmc_project/sensors/cfm/" + name,
98 "xyz.openbmc_project.Sensor.Value");
99
100 if (thresholds::hasWarningInterface(thresholds))
101 {
102 thresholdInterfaceWarning = objectServer.add_interface(
103 "/xyz/openbmc_project/sensors/cfm/" + name,
104 "xyz.openbmc_project.Sensor.Threshold.Warning");
105 }
106 if (thresholds::hasCriticalInterface(thresholds))
107 {
108 thresholdInterfaceCritical = objectServer.add_interface(
109 "/xyz/openbmc_project/sensors/cfm/" + name,
110 "xyz.openbmc_project.Sensor.Threshold.Critical");
111 }
James Feist078f2322019-03-08 11:09:05 -0800112
113 association = objectServer.add_interface(
114 "/xyz/openbmc_project/sensors/voltage/" + name,
115 "org.openbmc.Associations");
116
James Feistb2eb3f52018-12-04 16:17:50 -0800117 setInitialProperties(conn);
118 setupSensorMatch(
119 matches, *dbusConnection, "fan_tach",
120 std::move(
121 [this](const double& value, sdbusplus::message::message& message) {
122 tachReadings[message.get_path()] = value;
123 if (tachRanges.find(message.get_path()) == tachRanges.end())
124 {
125 // calls update reading after updating ranges
126 addTachRanges(message.get_sender(), message.get_path());
127 }
128 else
129 {
130 updateReading();
131 }
132 }));
133}
134
James Feist9566bfa2019-01-29 15:31:23 -0800135CFMSensor::~CFMSensor()
136{
137 objServer.remove_interface(thresholdInterfaceWarning);
138 objServer.remove_interface(thresholdInterfaceCritical);
139 objServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -0800140 objServer.remove_interface(association);
James Feist9566bfa2019-01-29 15:31:23 -0800141}
142
James Feistb2eb3f52018-12-04 16:17:50 -0800143void CFMSensor::addTachRanges(const std::string& serviceName,
144 const std::string& path)
145{
146 dbusConnection->async_method_call(
147 [this, path](const boost::system::error_code ec,
148 const boost::container::flat_map<std::string,
149 BasicVariantType>& data) {
150 if (ec)
151 {
152 std::cerr << "Error getting properties from " << path << "\n";
James Feist1ccdb5e2019-01-24 09:44:01 -0800153 return;
James Feistb2eb3f52018-12-04 16:17:50 -0800154 }
155
156 double max = loadVariant<double>(data, "MaxValue");
157 double min = loadVariant<double>(data, "MinValue");
158 tachRanges[path] = std::make_pair(min, max);
159 updateReading();
160 },
161 serviceName, path, "org.freedesktop.DBus.Properties", "GetAll",
162 "xyz.openbmc_project.Sensor.Value");
163}
164
165void CFMSensor::checkThresholds(void)
166{
167 thresholds::checkThresholds(this);
168}
169
170void CFMSensor::updateReading(void)
171{
172 double val = 0.0;
173 if (calculate(val))
174 {
175 if (value != val && parent)
176 {
177 parent->updateReading();
178 }
179 updateValue(val);
180 }
181 else
182 {
183 updateValue(std::numeric_limits<double>::quiet_NaN());
184 }
185}
186
187bool CFMSensor::calculate(double& value)
188{
189 double totalCFM = 0;
190 for (const std::string& tachName : tachs)
191 {
James Feist9566bfa2019-01-29 15:31:23 -0800192
James Feistb2eb3f52018-12-04 16:17:50 -0800193 auto findReading = std::find_if(
194 tachReadings.begin(), tachReadings.end(), [&](const auto& item) {
195 return boost::ends_with(item.first, tachName);
196 });
197 auto findRange = std::find_if(
198 tachRanges.begin(), tachRanges.end(), [&](const auto& item) {
199 return boost::ends_with(item.first, tachName);
200 });
201 if (findReading == tachReadings.end())
202 {
James Feista96329f2019-01-24 10:08:27 -0800203 if (DEBUG)
204 {
205 std::cerr << "Can't find " << tachName << "in readings\n";
206 }
James Feist9566bfa2019-01-29 15:31:23 -0800207 continue; // haven't gotten a reading
James Feistb2eb3f52018-12-04 16:17:50 -0800208 }
209
210 if (findRange == tachRanges.end())
211 {
James Feist523828e2019-03-04 14:38:37 -0800212 std::cerr << "Can't find " << tachName << " in ranges\n";
James Feistb2eb3f52018-12-04 16:17:50 -0800213 return false; // haven't gotten a max / min
214 }
215
216 // avoid divide by 0
217 if (findRange->second.second == 0)
218 {
219 std::cerr << "Tach Max Set to 0 " << tachName << "\n";
220 return false;
221 }
222
223 double rpm = findReading->second;
224
225 // for now assume the min for a fan is always 0, divide by max to get
226 // percent and mult by 100
227 rpm /= findRange->second.second;
228 rpm *= 100;
229
230 if constexpr (DEBUG)
231 {
232 std::cout << "Tach " << tachName << "at " << rpm << "\n";
233 }
234
235 // Do a linear interpolation to get Ci
236 // Ci = C1 + (C2 - C1)/(RPM2 - RPM1) * (TACHi - TACH1)
237
238 double ci = 0;
239 if (rpm == 0)
240 {
241 ci = 0;
242 }
243 else if (rpm < tachMinPercent)
244 {
245 ci = c1;
246 }
247 else if (rpm > tachMaxPercent)
248 {
249 ci = c2;
250 }
251 else
252 {
253 ci = c1 + (((c2 - c1) * (rpm - tachMinPercent)) /
254 (tachMaxPercent - tachMinPercent));
255 }
256
257 // Now calculate the CFM for this tach
258 // CFMi = Ci * Qmaxi * TACHi
259 totalCFM += ci * maxCFM * rpm;
260 }
261
262 // divide by 100 since rpm is in percent
263 value = totalCFM / 100;
James Feist9566bfa2019-01-29 15:31:23 -0800264 return true;
James Feistb2eb3f52018-12-04 16:17:50 -0800265}
266
267static constexpr double exitAirMaxReading = 127;
268static constexpr double exitAirMinReading = -128;
James Feistbc896df2018-11-26 16:28:17 -0800269ExitAirTempSensor::ExitAirTempSensor(
270 std::shared_ptr<sdbusplus::asio::connection>& conn,
James Feistb2eb3f52018-12-04 16:17:50 -0800271 const std::string& sensorName, const std::string& sensorConfiguration,
James Feistbc896df2018-11-26 16:28:17 -0800272 sdbusplus::asio::object_server& objectServer,
273 std::vector<thresholds::Threshold>&& thresholds) :
James Feistb2eb3f52018-12-04 16:17:50 -0800274 Sensor(boost::replace_all_copy(sensorName, " ", "_"),
275 "" /* todo: remove arg from base*/, std::move(thresholds),
276 sensorConfiguration, "xyz.openbmc_project.Configuration.ExitAirTemp",
277 exitAirMaxReading, exitAirMinReading),
James Feist523828e2019-03-04 14:38:37 -0800278 dbusConnection(conn), objServer(objectServer)
James Feistbc896df2018-11-26 16:28:17 -0800279{
280 sensorInterface = objectServer.add_interface(
281 "/xyz/openbmc_project/sensors/temperature/" + name,
282 "xyz.openbmc_project.Sensor.Value");
283
284 if (thresholds::hasWarningInterface(thresholds))
285 {
286 thresholdInterfaceWarning = objectServer.add_interface(
287 "/xyz/openbmc_project/sensors/temperature/" + name,
288 "xyz.openbmc_project.Sensor.Threshold.Warning");
289 }
290 if (thresholds::hasCriticalInterface(thresholds))
291 {
292 thresholdInterfaceCritical = objectServer.add_interface(
293 "/xyz/openbmc_project/sensors/temperature/" + name,
294 "xyz.openbmc_project.Sensor.Threshold.Critical");
295 }
James Feist078f2322019-03-08 11:09:05 -0800296 association = objectServer.add_interface(
297 "/xyz/openbmc_project/sensors/temperature/" + name,
298 "org.openbmc.Associations");
James Feistbc896df2018-11-26 16:28:17 -0800299 setInitialProperties(conn);
300 setupMatches();
James Feist71d31b22019-01-02 16:57:54 -0800301 setupPowerMatch(conn);
James Feistbc896df2018-11-26 16:28:17 -0800302}
303
304ExitAirTempSensor::~ExitAirTempSensor()
305{
James Feist523828e2019-03-04 14:38:37 -0800306 objServer.remove_interface(thresholdInterfaceWarning);
307 objServer.remove_interface(thresholdInterfaceCritical);
308 objServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -0800309 objServer.remove_interface(association);
James Feistbc896df2018-11-26 16:28:17 -0800310}
311
312void ExitAirTempSensor::setupMatches(void)
313{
314
James Feistb2eb3f52018-12-04 16:17:50 -0800315 constexpr const std::array<const char*, 2> matchTypes = {
316 "power", inletTemperatureSensor};
James Feistbc896df2018-11-26 16:28:17 -0800317
James Feistb2eb3f52018-12-04 16:17:50 -0800318 for (const std::string& type : matchTypes)
James Feistbc896df2018-11-26 16:28:17 -0800319 {
James Feistb2eb3f52018-12-04 16:17:50 -0800320 setupSensorMatch(matches, *dbusConnection, type,
321 [this, type](const double& value,
322 sdbusplus::message::message& message) {
323 if (type == "power")
324 {
325 powerReadings[message.get_path()] = value;
326 }
327 else if (type == inletTemperatureSensor)
328 {
329 inletTemp = value;
330 }
331 updateReading();
332 });
James Feistbc896df2018-11-26 16:28:17 -0800333 }
James Feist9566bfa2019-01-29 15:31:23 -0800334 dbusConnection->async_method_call(
335 [this](boost::system::error_code ec,
336 const std::variant<double>& value) {
337 if (ec)
338 {
339 // sensor not ready yet
340 return;
341 }
342
James Feist3eb82622019-02-08 13:10:22 -0800343 inletTemp = std::visit(VariantToDoubleVisitor(), value);
James Feist9566bfa2019-01-29 15:31:23 -0800344 },
345 "xyz.openbmc_project.HwmonTempSensor",
346 std::string("/xyz/openbmc_project/sensors/") + inletTemperatureSensor,
347 "org.freedesktop.DBus.Properties", "Get",
348 "xyz.openbmc_project.Sensor.Value", "Value");
James Feistbc896df2018-11-26 16:28:17 -0800349}
350
351void ExitAirTempSensor::updateReading(void)
352{
353
354 double val = 0.0;
355 if (calculate(val))
356 {
James Feist18af4232019-03-13 11:14:00 -0700357 val = std::floor(val + 0.5);
James Feistbc896df2018-11-26 16:28:17 -0800358 updateValue(val);
359 }
360 else
361 {
362 updateValue(std::numeric_limits<double>::quiet_NaN());
363 }
364}
365
James Feistb2eb3f52018-12-04 16:17:50 -0800366double ExitAirTempSensor::getTotalCFM(void)
James Feistbc896df2018-11-26 16:28:17 -0800367{
James Feistb2eb3f52018-12-04 16:17:50 -0800368 double sum = 0;
369 for (auto& sensor : cfmSensors)
James Feistbc896df2018-11-26 16:28:17 -0800370 {
James Feistb2eb3f52018-12-04 16:17:50 -0800371 double reading = 0;
372 if (!sensor->calculate(reading))
James Feistbc896df2018-11-26 16:28:17 -0800373 {
James Feistbc896df2018-11-26 16:28:17 -0800374 return -1;
375 }
James Feistb2eb3f52018-12-04 16:17:50 -0800376 sum += reading;
James Feistbc896df2018-11-26 16:28:17 -0800377 }
James Feistb2eb3f52018-12-04 16:17:50 -0800378
379 return sum;
James Feistbc896df2018-11-26 16:28:17 -0800380}
381
382bool ExitAirTempSensor::calculate(double& val)
383{
384 static bool firstRead = false;
385 double cfm = getTotalCFM();
386 if (cfm <= 0)
387 {
388 std::cerr << "Error getting cfm\n";
389 return false;
390 }
391
392 // if there is an error getting inlet temp, return error
393 if (std::isnan(inletTemp))
394 {
395 std::cerr << "Cannot get inlet temp\n";
396 val = 0;
397 return false;
398 }
399
400 // if fans are off, just make the exit temp equal to inlet
James Feist71d31b22019-01-02 16:57:54 -0800401 if (!isPowerOn())
James Feistbc896df2018-11-26 16:28:17 -0800402 {
403 val = inletTemp;
404 return true;
405 }
406
407 double totalPower = 0;
408 for (const auto& reading : powerReadings)
409 {
410 if (std::isnan(reading.second))
411 {
412 continue;
413 }
414 totalPower += reading.second;
415 }
416
417 // Calculate power correction factor
418 // Ci = CL + (CH - CL)/(QMax - QMin) * (CFM - QMin)
419 float powerFactor = 0.0;
420 if (cfm <= qMin)
421 {
422 powerFactor = powerFactorMin;
423 }
424 else if (cfm >= qMax)
425 {
426 powerFactor = powerFactorMax;
427 }
428 else
429 {
430 powerFactor = powerFactorMin + ((powerFactorMax - powerFactorMin) /
431 (qMax - qMin) * (cfm - qMin));
432 }
433
434 totalPower *= powerFactor;
435 totalPower += pOffset;
436
437 if (totalPower == 0)
438 {
439 std::cerr << "total power 0\n";
440 val = 0;
441 return false;
442 }
443
444 if constexpr (DEBUG)
445 {
446 std::cout << "Power Factor " << powerFactor << "\n";
447 std::cout << "Inlet Temp " << inletTemp << "\n";
448 std::cout << "Total Power" << totalPower << "\n";
449 }
450
451 // Calculate the exit air temp
452 // Texit = Tfp + (1.76 * TotalPower / CFM * Faltitude)
453 double reading = 1.76 * totalPower * altitudeFactor;
454 reading /= cfm;
455 reading += inletTemp;
456
457 if constexpr (DEBUG)
458 {
459 std::cout << "Reading 1: " << reading << "\n";
460 }
461
462 // Now perform the exponential average
463 // Calculate alpha based on SDR values and CFM
464 // Ai = As + (Af - As)/(QMax - QMin) * (CFM - QMin)
465
466 double alpha = 0.0;
467 if (cfm < qMin)
468 {
469 alpha = alphaS;
470 }
471 else if (cfm >= qMax)
472 {
473 alpha = alphaF;
474 }
475 else
476 {
477 alpha = alphaS + ((alphaF - alphaS) * (cfm - qMin) / (qMax - qMin));
478 }
479
480 auto time = std::chrono::system_clock::now();
481 if (!firstRead)
482 {
483 firstRead = true;
484 lastTime = time;
485 lastReading = reading;
486 }
487 double alphaDT =
488 std::chrono::duration_cast<std::chrono::seconds>(time - lastTime)
489 .count() *
490 alpha;
491
492 // cap at 1.0 or the below fails
493 if (alphaDT > 1.0)
494 {
495 alphaDT = 1.0;
496 }
497
498 if constexpr (DEBUG)
499 {
500 std::cout << "AlphaDT: " << alphaDT << "\n";
501 }
502
503 reading = ((reading * alphaDT) + (lastReading * (1.0 - alphaDT)));
504
505 if constexpr (DEBUG)
506 {
507 std::cout << "Reading 2: " << reading << "\n";
508 }
509
510 val = reading;
511 lastReading = reading;
512 lastTime = time;
513 return true;
514}
515
516void ExitAirTempSensor::checkThresholds(void)
517{
518 thresholds::checkThresholds(this);
519}
520
James Feistbc896df2018-11-26 16:28:17 -0800521static void loadVariantPathArray(
522 const boost::container::flat_map<std::string, BasicVariantType>& data,
523 const std::string& key, std::vector<std::string>& resp)
524{
525 auto it = data.find(key);
526 if (it == data.end())
527 {
528 std::cerr << "Configuration missing " << key << "\n";
529 throw std::invalid_argument("Key Missing");
530 }
531 BasicVariantType copy = it->second;
James Feist3eb82622019-02-08 13:10:22 -0800532 std::vector<std::string> config = std::get<std::vector<std::string>>(copy);
James Feistbc896df2018-11-26 16:28:17 -0800533 for (auto& str : config)
534 {
535 boost::replace_all(str, " ", "_");
536 }
537 resp = std::move(config);
538}
539
540void createSensor(sdbusplus::asio::object_server& objectServer,
James Feistb2eb3f52018-12-04 16:17:50 -0800541 std::shared_ptr<ExitAirTempSensor>& exitAirSensor,
James Feistbc896df2018-11-26 16:28:17 -0800542 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
543{
544 if (!dbusConnection)
545 {
546 std::cerr << "Connection not created\n";
547 return;
548 }
549 dbusConnection->async_method_call(
550 [&](boost::system::error_code ec, const ManagedObjectType& resp) {
551 if (ec)
552 {
553 std::cerr << "Error contacting entity manager\n";
554 return;
555 }
James Feistb2eb3f52018-12-04 16:17:50 -0800556 std::vector<std::unique_ptr<CFMSensor>> cfmSensors;
James Feistbc896df2018-11-26 16:28:17 -0800557 for (const auto& pathPair : resp)
558 {
559 for (const auto& entry : pathPair.second)
560 {
561 if (entry.first == exitAirIface)
562 {
James Feistbc896df2018-11-26 16:28:17 -0800563 // thresholds should be under the same path
564 std::vector<thresholds::Threshold> sensorThresholds;
565 parseThresholdsFromConfig(pathPair.second,
566 sensorThresholds);
James Feistbc896df2018-11-26 16:28:17 -0800567
James Feist523828e2019-03-04 14:38:37 -0800568 std::string name =
569 loadVariant<std::string>(entry.second, "Name");
570 exitAirSensor = std::make_shared<ExitAirTempSensor>(
571 dbusConnection, name, pathPair.first.str,
572 objectServer, std::move(sensorThresholds));
James Feistb2eb3f52018-12-04 16:17:50 -0800573 exitAirSensor->powerFactorMin =
574 loadVariant<double>(entry.second, "PowerFactorMin");
575 exitAirSensor->powerFactorMax =
576 loadVariant<double>(entry.second, "PowerFactorMax");
577 exitAirSensor->qMin =
578 loadVariant<double>(entry.second, "QMin");
579 exitAirSensor->qMax =
580 loadVariant<double>(entry.second, "QMax");
581 exitAirSensor->alphaS =
582 loadVariant<double>(entry.second, "AlphaS");
583 exitAirSensor->alphaF =
584 loadVariant<double>(entry.second, "AlphaF");
James Feistbc896df2018-11-26 16:28:17 -0800585 }
586 else if (entry.first == cfmIface)
587
588 {
James Feistb2eb3f52018-12-04 16:17:50 -0800589 // thresholds should be under the same path
590 std::vector<thresholds::Threshold> sensorThresholds;
591 parseThresholdsFromConfig(pathPair.second,
592 sensorThresholds);
593 std::string name =
594 loadVariant<std::string>(entry.second, "Name");
595 auto sensor = std::make_unique<CFMSensor>(
596 dbusConnection, name, pathPair.first.str,
597 objectServer, std::move(sensorThresholds),
598 exitAirSensor);
599 loadVariantPathArray(entry.second, "Tachs",
600 sensor->tachs);
601 sensor->maxCFM =
602 loadVariant<double>(entry.second, "MaxCFM");
James Feistbc896df2018-11-26 16:28:17 -0800603
604 // change these into percent upon getting the data
James Feistb2eb3f52018-12-04 16:17:50 -0800605 sensor->c1 =
606 loadVariant<double>(entry.second, "C1") / 100;
607 sensor->c2 =
608 loadVariant<double>(entry.second, "C2") / 100;
609 sensor->tachMinPercent =
610 loadVariant<double>(entry.second,
611 "TachMinPercent") /
James Feistbc896df2018-11-26 16:28:17 -0800612 100;
James Feistb2eb3f52018-12-04 16:17:50 -0800613 sensor->tachMaxPercent =
614 loadVariant<double>(entry.second,
615 "TachMaxPercent") /
James Feistbc896df2018-11-26 16:28:17 -0800616 100;
617
James Feistb2eb3f52018-12-04 16:17:50 -0800618 cfmSensors.emplace_back(std::move(sensor));
James Feistbc896df2018-11-26 16:28:17 -0800619 }
620 }
621 }
James Feistb2eb3f52018-12-04 16:17:50 -0800622 if (exitAirSensor)
James Feistbc896df2018-11-26 16:28:17 -0800623 {
James Feistb2eb3f52018-12-04 16:17:50 -0800624 exitAirSensor->cfmSensors = std::move(cfmSensors);
James Feistbc896df2018-11-26 16:28:17 -0800625
James Feistb2eb3f52018-12-04 16:17:50 -0800626 // todo: when power sensors are done delete this fake
627 // reading
628 exitAirSensor->powerReadings["foo"] = 144.0;
James Feistbc896df2018-11-26 16:28:17 -0800629
James Feistb2eb3f52018-12-04 16:17:50 -0800630 exitAirSensor->updateReading();
James Feistbc896df2018-11-26 16:28:17 -0800631 }
632 },
633 entityManagerName, "/", "org.freedesktop.DBus.ObjectManager",
634 "GetManagedObjects");
635}
636
637int main(int argc, char** argv)
638{
639
640 boost::asio::io_service io;
641 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
642 systemBus->request_name("xyz.openbmc_project.ExitAirTempSensor");
643 sdbusplus::asio::object_server objectServer(systemBus);
644 std::shared_ptr<ExitAirTempSensor> sensor =
645 nullptr; // wait until we find the config
646 std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches;
647
648 io.post([&]() { createSensor(objectServer, sensor, systemBus); });
649
650 boost::asio::deadline_timer configTimer(io);
651
652 std::function<void(sdbusplus::message::message&)> eventHandler =
653 [&](sdbusplus::message::message& message) {
654 configTimer.expires_from_now(boost::posix_time::seconds(1));
655 // create a timer because normally multiple properties change
656 configTimer.async_wait([&](const boost::system::error_code& ec) {
657 if (ec == boost::asio::error::operation_aborted)
658 {
659 return; // we're being canceled
660 }
661 createSensor(objectServer, sensor, systemBus);
662 if (!sensor)
663 {
664 std::cout << "Configuration not detected\n";
665 }
666 });
667 };
668 constexpr const std::array<const char*, 2> monitorIfaces = {exitAirIface,
669 cfmIface};
670 for (const char* type : monitorIfaces)
671 {
672 auto match = std::make_unique<sdbusplus::bus::match::match>(
673 static_cast<sdbusplus::bus::bus&>(*systemBus),
674 "type='signal',member='PropertiesChanged',path_namespace='" +
675 std::string(inventoryPath) + "',arg0namespace='" + type + "'",
676 eventHandler);
677 matches.emplace_back(std::move(match));
678 }
679
680 io.run();
681}