health metric: check hysteresis for value notify

Add hysteresis for metric value and check it before notifying the metric
value update.

Change-Id: I8dace4b9436dd9b16f1a075505079d5001928f52
Signed-off-by: Jagpal Singh Gill <paligill@gmail.com>
diff --git a/health_metric.cpp b/health_metric.cpp
index 31feb55..2f23394 100644
--- a/health_metric.cpp
+++ b/health_metric.cpp
@@ -2,6 +2,7 @@
 
 #include <phosphor-logging/lg2.hpp>
 
+#include <cmath>
 #include <numeric>
 #include <unordered_map>
 
@@ -12,6 +13,8 @@
 
 using association_t = std::tuple<std::string, std::string, std::string>;
 
+static constexpr double hysteresis = 1.0;
+
 auto HealthMetric::getPath(MType type, std::string name, SubType subType)
     -> std::string
 {
@@ -205,9 +208,25 @@
     }
 }
 
+auto HealthMetric::shouldNotify(MValue value) -> bool
+{
+    if (std::isnan(value.current))
+    {
+        return true;
+    }
+    auto changed = std::abs((value.current - lastNotifiedValue) /
+                            lastNotifiedValue * 100.0);
+    if (changed >= hysteresis)
+    {
+        lastNotifiedValue = value.current;
+        return true;
+    }
+    return false;
+}
+
 void HealthMetric::update(MValue value)
 {
-    ValueIntf::value(value.current);
+    ValueIntf::value(value.current, !shouldNotify(value));
 
     // Maintain window size for threshold calculation
     if (history.size() >= config.windowSize)
diff --git a/health_metric.hpp b/health_metric.hpp
index 9584953..cf2f66b 100644
--- a/health_metric.hpp
+++ b/health_metric.hpp
@@ -62,6 +62,9 @@
     void create(const paths_t& bmcPaths);
     /** @brief Init properties for the health metric object */
     void initProperties();
+    /** @brief Check if specified value should be notified based on hysteresis
+     */
+    auto shouldNotify(MValue value) -> bool;
     /** @brief Check specified threshold for the given value */
     void checkThreshold(Type type, Bound bound, MValue value);
     /** @brief Check all thresholds for the given value */
@@ -76,6 +79,8 @@
     const config::HealthMetric config;
     /** @brief Window for metric history */
     std::deque<double> history;
+    /** @brief Last notified value for the metric change */
+    double lastNotifiedValue = 0;
 };
 
 } // namespace phosphor::health::metric