Add base class to simplify threshold logic

Add base class for the default case check_thresholds
calls the thresholds.cpp function. This way for normal
things we can just pass sensors around as the base class.

Make it so that theshold alerts are only sent once.

Change-Id: Ic8e3ae1900aeb12b74c099f637f45bc038bd3c9a
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/include/sensor.hpp b/include/sensor.hpp
new file mode 100644
index 0000000..2f746da
--- /dev/null
+++ b/include/sensor.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <Thresholds.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+
+struct Sensor
+{
+    virtual ~Sensor() = default;
+    std::vector<thresholds::Threshold> thresholds;
+    std::shared_ptr<sdbusplus::asio::dbus_interface> sensorInterface;
+    std::shared_ptr<sdbusplus::asio::dbus_interface> thresholdInterfaceWarning;
+    std::shared_ptr<sdbusplus::asio::dbus_interface> thresholdInterfaceCritical;
+    double value = std::numeric_limits<double>::quiet_NaN();
+};
\ No newline at end of file
diff --git a/sensors/include/ADCSensor.hpp b/sensors/include/ADCSensor.hpp
index 07c7893..d59bd5f 100644
--- a/sensors/include/ADCSensor.hpp
+++ b/sensors/include/ADCSensor.hpp
@@ -2,8 +2,9 @@
 
 #include <Thresholds.hpp>
 #include <sdbusplus/asio/object_server.hpp>
+#include <sensor.hpp>
 
-class ADCSensor
+class ADCSensor : public Sensor
 {
   public:
     std::string name;
@@ -20,16 +21,9 @@
   private:
     std::string path;
     sdbusplus::asio::object_server &objServer;
-    std::vector<thresholds::Threshold> thresholds;
-    std::shared_ptr<sdbusplus::asio::dbus_interface> sensor_interface;
-    std::shared_ptr<sdbusplus::asio::dbus_interface>
-        threshold_interface_warning;
-    std::shared_ptr<sdbusplus::asio::dbus_interface>
-        threshold_interface_critical;
     boost::asio::posix::stream_descriptor input_dev;
     boost::asio::deadline_timer wait_timer;
     boost::asio::streambuf read_buf;
-    double value;
     int err_count;
     double max_value;
     double min_value;
@@ -38,8 +32,7 @@
     void handle_response(const boost::system::error_code &err);
     void check_thresholds(void);
     void update_value(const double &new_value);
-    void assert_thresholds(thresholds::Level level,
-                           thresholds::Direction direction, bool assert);
+
     void set_initial_properties(
         std::shared_ptr<sdbusplus::asio::connection> &conn);
 };
\ No newline at end of file
diff --git a/sensors/include/CPUSensor.hpp b/sensors/include/CPUSensor.hpp
index 85ae831..8f7d2f0 100644
--- a/sensors/include/CPUSensor.hpp
+++ b/sensors/include/CPUSensor.hpp
@@ -2,8 +2,9 @@
 
 #include <Thresholds.hpp>
 #include <sdbusplus/asio/object_server.hpp>
+#include <sensor.hpp>
 
-class CPUSensor
+class CPUSensor : public Sensor
 {
   private:
     std::string path;
@@ -11,16 +12,9 @@
     sdbusplus::asio::object_server &objServer;
     std::shared_ptr<sdbusplus::asio::connection> dbusConnection;
     std::string name;
-    std::vector<thresholds::Threshold> thresholds;
-    std::shared_ptr<sdbusplus::asio::dbus_interface> sensor_interface;
-    std::shared_ptr<sdbusplus::asio::dbus_interface>
-        threshold_interface_warning;
-    std::shared_ptr<sdbusplus::asio::dbus_interface>
-        threshold_interface_critical;
     boost::asio::posix::stream_descriptor input_dev;
     boost::asio::deadline_timer wait_timer;
     boost::asio::streambuf read_buf;
-    double value;
     int err_count;
     double max_value;
     double min_value;
@@ -28,8 +22,7 @@
     void handle_response(const boost::system::error_code &err);
     void check_thresholds(void);
     void update_value(const double &new_value);
-    void assert_thresholds(thresholds::Level level,
-                           thresholds::Direction direction, bool assert);
+
     void set_initial_properties(
         std::shared_ptr<sdbusplus::asio::connection> &conn);
 
diff --git a/sensors/include/HwmonTempSensor.hpp b/sensors/include/HwmonTempSensor.hpp
index 58eb534..ebdaea6 100644
--- a/sensors/include/HwmonTempSensor.hpp
+++ b/sensors/include/HwmonTempSensor.hpp
@@ -2,8 +2,9 @@
 
 #include <Thresholds.hpp>
 #include <sdbusplus/asio/object_server.hpp>
+#include <sensor.hpp>
 
-class HwmonTempSensor
+class HwmonTempSensor : public Sensor
 {
   public:
     std::string name;
@@ -20,16 +21,9 @@
     std::string path;
     std::string objectType;
     sdbusplus::asio::object_server &objServer;
-    std::vector<thresholds::Threshold> thresholds;
-    std::shared_ptr<sdbusplus::asio::dbus_interface> sensor_interface;
-    std::shared_ptr<sdbusplus::asio::dbus_interface>
-        threshold_interface_warning;
-    std::shared_ptr<sdbusplus::asio::dbus_interface>
-        threshold_interface_critical;
     boost::asio::posix::stream_descriptor input_dev;
     boost::asio::deadline_timer wait_timer;
     boost::asio::streambuf read_buf;
-    double value;
     int err_count;
     double max_value;
     double min_value;
@@ -37,8 +31,7 @@
     void handle_response(const boost::system::error_code &err);
     void check_thresholds(void);
     void update_value(const double &new_value);
-    void assert_thresholds(thresholds::Level level,
-                           thresholds::Direction direction, bool assert);
+
     void set_initial_properties(
         std::shared_ptr<sdbusplus::asio::connection> &conn);
 };
\ No newline at end of file
diff --git a/sensors/include/TachSensor.hpp b/sensors/include/TachSensor.hpp
index 2c8b535..e352855 100644
--- a/sensors/include/TachSensor.hpp
+++ b/sensors/include/TachSensor.hpp
@@ -2,8 +2,9 @@
 
 #include <Thresholds.hpp>
 #include <sdbusplus/asio/object_server.hpp>
+#include <sensor.hpp>
 
-class TachSensor
+class TachSensor : public Sensor
 {
   public:
     std::string name;
@@ -20,16 +21,9 @@
     std::string path;
     sdbusplus::asio::object_server &objServer;
     std::shared_ptr<sdbusplus::asio::connection> dbusConnection;
-    std::vector<thresholds::Threshold> thresholds;
-    std::shared_ptr<sdbusplus::asio::dbus_interface> sensor_interface;
-    std::shared_ptr<sdbusplus::asio::dbus_interface>
-        threshold_interface_warning;
-    std::shared_ptr<sdbusplus::asio::dbus_interface>
-        threshold_interface_critical;
     boost::asio::posix::stream_descriptor input_dev;
     boost::asio::deadline_timer wait_timer;
     boost::asio::streambuf read_buf;
-    double value;
     int err_count;
     double max_value;
     double min_value;
@@ -37,8 +31,7 @@
     void handle_response(const boost::system::error_code &err);
     void check_thresholds(void);
     void update_value(const double &new_value);
-    void assert_thresholds(thresholds::Level level,
-                           thresholds::Direction direction, bool assert);
+
     void set_initial_properties(
         std::shared_ptr<sdbusplus::asio::connection> &conn);
 };
diff --git a/sensors/include/Thresholds.hpp b/sensors/include/Thresholds.hpp
index 5b194c6..90e148c 100644
--- a/sensors/include/Thresholds.hpp
+++ b/sensors/include/Thresholds.hpp
@@ -2,6 +2,7 @@
 #include <Utils.hpp>
 #include <nlohmann/json.hpp>
 
+struct Sensor;
 namespace thresholds
 {
 enum Level
@@ -26,6 +27,7 @@
     Direction direction;
     double value;
     bool writeable;
+    bool asserted = false;
 };
 
 bool ParseThresholdsFromConfig(
@@ -38,10 +40,15 @@
                              const double scale_factor);
 bool HasCriticalInterface(
     const std::vector<thresholds::Threshold> &threshold_vector);
+
 bool HasWarningInterface(
     const std::vector<thresholds::Threshold> &threshold_vector);
 
 void persistThreshold(const std::string &baseInterface, const std::string &path,
                       const thresholds::Threshold &threshold,
                       std::shared_ptr<sdbusplus::asio::connection> &conn);
+
+void checkThresholds(Sensor *sensor);
+void assertThresholds(Sensor *sensor, thresholds::Level level,
+                      thresholds::Direction direction, bool assert);
 } // namespace thresholds
diff --git a/sensors/src/ADCSensor.cpp b/sensors/src/ADCSensor.cpp
index 1ac0988..b72f5c1 100644
--- a/sensors/src/ADCSensor.cpp
+++ b/sensors/src/ADCSensor.cpp
@@ -40,27 +40,27 @@
                      std::vector<thresholds::Threshold> &&_thresholds,
                      const double scale_factor,
                      const std::string &sensorConfiguration) :
-    path(path),
-    objServer(objectServer), configuration(sensorConfiguration),
+    Sensor(),
+    path(path), objServer(objectServer), configuration(sensorConfiguration),
     name(boost::replace_all_copy(sensor_name, " ", "_")),
-    thresholds(std::move(_thresholds)), scale_factor(scale_factor),
-    sensor_interface(objectServer.add_interface(
-        "/xyz/openbmc_project/sensors/voltage/" + name,
-        "xyz.openbmc_project.Sensor.Value")),
-    input_dev(io, open(path.c_str(), O_RDONLY)), wait_timer(io),
-    value(std::numeric_limits<double>::quiet_NaN()), err_count(0),
+    scale_factor(scale_factor), input_dev(io, open(path.c_str(), O_RDONLY)),
+    wait_timer(io), err_count(0),
     // todo, get these from config
     max_value(20), min_value(0)
 {
+    thresholds = std::move(_thresholds);
+    sensorInterface = objectServer.add_interface(
+        "/xyz/openbmc_project/sensors/voltage/" + name,
+        "xyz.openbmc_project.Sensor.Value");
     if (thresholds::HasWarningInterface(thresholds))
     {
-        threshold_interface_warning = objectServer.add_interface(
+        thresholdInterfaceWarning = objectServer.add_interface(
             "/xyz/openbmc_project/sensors/voltage/" + name,
             "xyz.openbmc_project.Sensor.Threshold.Warning");
     }
     if (thresholds::HasCriticalInterface(thresholds))
     {
-        threshold_interface_critical = objectServer.add_interface(
+        thresholdInterfaceCritical = objectServer.add_interface(
             "/xyz/openbmc_project/sensors/voltage/" + name,
             "xyz.openbmc_project.Sensor.Threshold.Critical");
     }
@@ -73,9 +73,9 @@
     // close the input dev to cancel async operations
     input_dev.close();
     wait_timer.cancel();
-    objServer.remove_interface(threshold_interface_warning);
-    objServer.remove_interface(threshold_interface_critical);
-    objServer.remove_interface(sensor_interface);
+    objServer.remove_interface(thresholdInterfaceWarning);
+    objServer.remove_interface(thresholdInterfaceCritical);
+    objServer.remove_interface(sensorInterface);
 }
 
 void ADCSensor::setup_read(void)
@@ -152,92 +152,23 @@
 
 void ADCSensor::check_thresholds(void)
 {
-    if (thresholds.empty())
-        return;
-    for (auto threshold : thresholds)
-    {
-        if (threshold.direction == thresholds::Direction::HIGH)
-        {
-            if (value > threshold.value)
-            {
-                assert_thresholds(threshold.level, threshold.direction, true);
-            }
-            else
-            {
-                assert_thresholds(threshold.level, threshold.direction, false);
-            }
-        }
-        else
-        {
-            if (value < threshold.value)
-            {
-                assert_thresholds(threshold.level, threshold.direction, true);
-            }
-            else
-            {
-                assert_thresholds(threshold.level, threshold.direction, false);
-            }
-        }
-    }
+    thresholds::checkThresholds(this);
 }
 
 void ADCSensor::update_value(const double &new_value)
 {
-    bool ret = sensor_interface->set_property("Value", new_value);
+    bool ret = sensorInterface->set_property("Value", new_value);
     value = new_value;
     check_thresholds();
 }
 
-void ADCSensor::assert_thresholds(thresholds::Level level,
-                                  thresholds::Direction direction, bool assert)
-{
-    std::string property;
-    std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
-    if (level == thresholds::Level::WARNING &&
-        direction == thresholds::Direction::HIGH)
-    {
-        property = "WarningAlarmHigh";
-        interface = threshold_interface_warning;
-    }
-    else if (level == thresholds::Level::WARNING &&
-             direction == thresholds::Direction::LOW)
-    {
-        property = "WarningAlarmLow";
-        interface = threshold_interface_warning;
-    }
-    else if (level == thresholds::Level::CRITICAL &&
-             direction == thresholds::Direction::HIGH)
-    {
-        property = "CriticalAlarmHigh";
-        interface = threshold_interface_critical;
-    }
-    else if (level == thresholds::Level::CRITICAL &&
-             direction == thresholds::Direction::LOW)
-    {
-        property = "CriticalAlarmLow";
-        interface = threshold_interface_critical;
-    }
-    else
-    {
-        std::cerr << "Unknown threshold, level " << level << "direction "
-                  << direction << "\n";
-        return;
-    }
-    if (!interface)
-    {
-        std::cout << "trying to set uninitialized interface\n";
-        return;
-    }
-    interface->set_property(property, assert);
-}
-
 void ADCSensor::set_initial_properties(
     std::shared_ptr<sdbusplus::asio::connection> &conn)
 {
     // todo, get max and min from configuration
-    sensor_interface->register_property("MaxValue", max_value);
-    sensor_interface->register_property("MinValue", min_value);
-    sensor_interface->register_property("Value", value);
+    sensorInterface->register_property("MaxValue", max_value);
+    sensorInterface->register_property("MinValue", min_value);
+    sensorInterface->register_property("Value", value);
 
     for (auto &threshold : thresholds)
     {
@@ -246,7 +177,7 @@
         std::string alarm;
         if (threshold.level == thresholds::Level::CRITICAL)
         {
-            iface = threshold_interface_critical;
+            iface = thresholdInterfaceCritical;
             if (threshold.direction == thresholds::Direction::HIGH)
             {
                 level = "CriticalHigh";
@@ -260,7 +191,7 @@
         }
         else if (threshold.level == thresholds::Level::WARNING)
         {
-            iface = threshold_interface_warning;
+            iface = thresholdInterfaceWarning;
             if (threshold.direction == thresholds::Direction::HIGH)
             {
                 level = "WarningHigh";
@@ -294,18 +225,16 @@
             });
         iface->register_property(alarm, false);
     }
-    if (!sensor_interface->initialize())
+    if (!sensorInterface->initialize())
     {
         std::cerr << "error initializing value interface\n";
     }
-    if (threshold_interface_warning &&
-        !threshold_interface_warning->initialize())
+    if (thresholdInterfaceWarning && !thresholdInterfaceWarning->initialize())
     {
         std::cerr << "error initializing warning threshold interface\n";
     }
 
-    if (threshold_interface_critical &&
-        !threshold_interface_critical->initialize())
+    if (thresholdInterfaceCritical && !thresholdInterfaceCritical->initialize())
     {
         std::cerr << "error initializing critical threshold interface\n";
     }
diff --git a/sensors/src/CPUSensor.cpp b/sensors/src/CPUSensor.cpp
index 66bca1f..ce9e60b 100644
--- a/sensors/src/CPUSensor.cpp
+++ b/sensors/src/CPUSensor.cpp
@@ -35,27 +35,28 @@
                      boost::asio::io_service &io, const std::string &sensorName,
                      std::vector<thresholds::Threshold> &&_thresholds,
                      const std::string &sensorConfiguration) :
-    path(path),
-    objectType(objectType), objServer(objectServer),
+    Sensor(),
+    path(path), objectType(objectType), objServer(objectServer),
     name(boost::replace_all_copy(sensorName, " ", "_")), dbusConnection(conn),
-    thresholds(std::move(_thresholds)), configuration(sensorConfiguration),
-    sensor_interface(objectServer.add_interface(
-        "/xyz/openbmc_project/sensors/temperature/" + name,
-        "xyz.openbmc_project.Sensor.Value")),
-    input_dev(io, open(path.c_str(), O_RDONLY)), wait_timer(io),
-    value(std::numeric_limits<double>::quiet_NaN()), err_count(0),
+    configuration(sensorConfiguration),
+
+    input_dev(io, open(path.c_str(), O_RDONLY)), wait_timer(io), err_count(0),
     // todo, get these from config
     max_value(127), min_value(-128)
 {
+    thresholds = std::move(_thresholds);
+    sensorInterface = objectServer.add_interface(
+        "/xyz/openbmc_project/sensors/temperature/" + name,
+        "xyz.openbmc_project.Sensor.Value");
     if (thresholds::HasWarningInterface(thresholds))
     {
-        threshold_interface_warning = objectServer.add_interface(
+        thresholdInterfaceWarning = objectServer.add_interface(
             "/xyz/openbmc_project/sensors/temperature/" + name,
             "xyz.openbmc_project.Sensor.Threshold.Warning");
     }
     if (thresholds::HasCriticalInterface(thresholds))
     {
-        threshold_interface_critical = objectServer.add_interface(
+        thresholdInterfaceCritical = objectServer.add_interface(
             "/xyz/openbmc_project/sensors/temperature/" + name,
             "xyz.openbmc_project.Sensor.Threshold.Critical");
     }
@@ -69,9 +70,9 @@
     // close the input dev to cancel async operations
     input_dev.close();
     wait_timer.cancel();
-    objServer.remove_interface(threshold_interface_warning);
-    objServer.remove_interface(threshold_interface_critical);
-    objServer.remove_interface(sensor_interface);
+    objServer.remove_interface(thresholdInterfaceWarning);
+    objServer.remove_interface(thresholdInterfaceCritical);
+    objServer.remove_interface(sensorInterface);
 }
 
 void CPUSensor::setup_read(void)
@@ -128,7 +129,7 @@
         else
         {
             err_count = 0; // check power again in 10 cycles
-            sensor_interface->set_property(
+            sensorInterface->set_property(
                 "Value", std::numeric_limits<double>::quiet_NaN());
         }
     }
@@ -154,92 +155,23 @@
 
 void CPUSensor::check_thresholds(void)
 {
-    if (thresholds.empty())
-        return;
-    for (auto threshold : thresholds)
-    {
-        if (threshold.direction == thresholds::Direction::HIGH)
-        {
-            if (value > threshold.value)
-            {
-                assert_thresholds(threshold.level, threshold.direction, true);
-            }
-            else
-            {
-                assert_thresholds(threshold.level, threshold.direction, false);
-            }
-        }
-        else
-        {
-            if (value < threshold.value)
-            {
-                assert_thresholds(threshold.level, threshold.direction, true);
-            }
-            else
-            {
-                assert_thresholds(threshold.level, threshold.direction, false);
-            }
-        }
-    }
+    thresholds::checkThresholds(this);
 }
 
 void CPUSensor::update_value(const double &new_value)
 {
-    sensor_interface->set_property("Value", new_value);
+    sensorInterface->set_property("Value", new_value);
     value = new_value;
     check_thresholds();
 }
 
-void CPUSensor::assert_thresholds(thresholds::Level level,
-                                  thresholds::Direction direction, bool assert)
-{
-    std::string property;
-    std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
-    if (level == thresholds::Level::WARNING &&
-        direction == thresholds::Direction::HIGH)
-    {
-        property = "WarningAlarmHigh";
-        interface = threshold_interface_warning;
-    }
-    else if (level == thresholds::Level::WARNING &&
-             direction == thresholds::Direction::LOW)
-    {
-        property = "WarningAlarmLow";
-        interface = threshold_interface_warning;
-    }
-    else if (level == thresholds::Level::CRITICAL &&
-             direction == thresholds::Direction::HIGH)
-    {
-        property = "CriticalAlarmHigh";
-        interface = threshold_interface_critical;
-    }
-    else if (level == thresholds::Level::CRITICAL &&
-             direction == thresholds::Direction::LOW)
-    {
-        property = "CriticalAlarmLow";
-        interface = threshold_interface_critical;
-    }
-    else
-    {
-        std::cerr << "Unknown threshold, level " << level << "direction "
-                  << direction << "\n";
-        return;
-    }
-    if (!interface)
-    {
-        std::cout << "trying to set uninitialized interface\n";
-        return;
-    }
-    interface->set_property(property, assert);
-}
-
 void CPUSensor::set_initial_properties(
     std::shared_ptr<sdbusplus::asio::connection> &conn)
 {
     // todo, get max and min from configuration
-    sensor_interface->register_property("MaxValue", max_value);
-    sensor_interface->register_property("MinValue", min_value);
-    sensor_interface->register_property("Value", value);
+    sensorInterface->register_property("MaxValue", max_value);
+    sensorInterface->register_property("MinValue", min_value);
+    sensorInterface->register_property("Value", value);
 
     for (auto &threshold : thresholds)
     {
@@ -248,7 +180,7 @@
         std::string alarm;
         if (threshold.level == thresholds::Level::CRITICAL)
         {
-            iface = threshold_interface_critical;
+            iface = thresholdInterfaceCritical;
             if (threshold.direction == thresholds::Direction::HIGH)
             {
                 level = "CriticalHigh";
@@ -262,7 +194,7 @@
         }
         else if (threshold.level == thresholds::Level::WARNING)
         {
-            iface = threshold_interface_warning;
+            iface = thresholdInterfaceWarning;
             if (threshold.direction == thresholds::Direction::HIGH)
             {
                 level = "WarningHigh";
@@ -302,18 +234,16 @@
         }
         iface->register_property(alarm, false);
     }
-    if (!sensor_interface->initialize())
+    if (!sensorInterface->initialize())
     {
         std::cerr << "error initializing value interface\n";
     }
-    if (threshold_interface_warning &&
-        !threshold_interface_warning->initialize())
+    if (thresholdInterfaceWarning && !thresholdInterfaceWarning->initialize())
     {
         std::cerr << "error initializing warning threshold interface\n";
     }
 
-    if (threshold_interface_critical &&
-        !threshold_interface_critical->initialize())
+    if (thresholdInterfaceCritical && !thresholdInterfaceCritical->initialize())
     {
         std::cerr << "error initializing critical threshold interface\n";
     }
diff --git a/sensors/src/HwmonTempSensor.cpp b/sensors/src/HwmonTempSensor.cpp
index c1db504..5d3251a 100644
--- a/sensors/src/HwmonTempSensor.cpp
+++ b/sensors/src/HwmonTempSensor.cpp
@@ -37,28 +37,28 @@
     boost::asio::io_service &io, const std::string &sensor_name,
     std::vector<thresholds::Threshold> &&_thresholds,
     const std::string &sensorConfiguration) :
-    path(path),
-    objectType(objectType), configuration(sensorConfiguration),
+    Sensor(),
+    path(path), objectType(objectType), configuration(sensorConfiguration),
     objServer(objectServer),
     name(boost::replace_all_copy(sensor_name, " ", "_")),
-    thresholds(std::move(_thresholds)),
-    sensor_interface(objectServer.add_interface(
-        "/xyz/openbmc_project/sensors/temperature/" + name,
-        "xyz.openbmc_project.Sensor.Value")),
-    input_dev(io, open(path.c_str(), O_RDONLY)), wait_timer(io),
-    value(std::numeric_limits<double>::quiet_NaN()), err_count(0),
+    input_dev(io, open(path.c_str(), O_RDONLY)), wait_timer(io), err_count(0),
     // todo, get these from config
     max_value(127), min_value(-128)
 {
+    thresholds = std::move(_thresholds);
+    sensorInterface = objectServer.add_interface(
+        "/xyz/openbmc_project/sensors/temperature/" + name,
+        "xyz.openbmc_project.Sensor.Value");
+
     if (thresholds::HasWarningInterface(thresholds))
     {
-        threshold_interface_warning = objectServer.add_interface(
+        thresholdInterfaceWarning = objectServer.add_interface(
             "/xyz/openbmc_project/sensors/temperature/" + name,
             "xyz.openbmc_project.Sensor.Threshold.Warning");
     }
     if (thresholds::HasCriticalInterface(thresholds))
     {
-        threshold_interface_critical = objectServer.add_interface(
+        thresholdInterfaceCritical = objectServer.add_interface(
             "/xyz/openbmc_project/sensors/temperature/" + name,
             "xyz.openbmc_project.Sensor.Threshold.Critical");
     }
@@ -71,9 +71,9 @@
     // close the input dev to cancel async operations
     input_dev.close();
     wait_timer.cancel();
-    objServer.remove_interface(threshold_interface_warning);
-    objServer.remove_interface(threshold_interface_critical);
-    objServer.remove_interface(sensor_interface);
+    objServer.remove_interface(thresholdInterfaceWarning);
+    objServer.remove_interface(thresholdInterfaceCritical);
+    objServer.remove_interface(sensorInterface);
 }
 
 void HwmonTempSensor::setup_read(void)
@@ -144,93 +144,23 @@
 
 void HwmonTempSensor::check_thresholds(void)
 {
-    if (thresholds.empty())
-        return;
-    for (auto threshold : thresholds)
-    {
-        if (threshold.direction == thresholds::Direction::HIGH)
-        {
-            if (value > threshold.value)
-            {
-                assert_thresholds(threshold.level, threshold.direction, true);
-            }
-            else
-            {
-                assert_thresholds(threshold.level, threshold.direction, false);
-            }
-        }
-        else
-        {
-            if (value < threshold.value)
-            {
-                assert_thresholds(threshold.level, threshold.direction, true);
-            }
-            else
-            {
-                assert_thresholds(threshold.level, threshold.direction, false);
-            }
-        }
-    }
+    thresholds::checkThresholds(this);
 }
 
 void HwmonTempSensor::update_value(const double &new_value)
 {
-    sensor_interface->set_property("Value", new_value);
+    sensorInterface->set_property("Value", new_value);
     value = new_value;
     check_thresholds();
 }
 
-void HwmonTempSensor::assert_thresholds(thresholds::Level level,
-                                        thresholds::Direction direction,
-                                        bool assert)
-{
-    std::string property;
-    std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
-    if (level == thresholds::Level::WARNING &&
-        direction == thresholds::Direction::HIGH)
-    {
-        property = "WarningAlarmHigh";
-        interface = threshold_interface_warning;
-    }
-    else if (level == thresholds::Level::WARNING &&
-             direction == thresholds::Direction::LOW)
-    {
-        property = "WarningAlarmLow";
-        interface = threshold_interface_warning;
-    }
-    else if (level == thresholds::Level::CRITICAL &&
-             direction == thresholds::Direction::HIGH)
-    {
-        property = "CriticalAlarmHigh";
-        interface = threshold_interface_critical;
-    }
-    else if (level == thresholds::Level::CRITICAL &&
-             direction == thresholds::Direction::LOW)
-    {
-        property = "CriticalAlarmLow";
-        interface = threshold_interface_critical;
-    }
-    else
-    {
-        std::cerr << "Unknown threshold, level " << level << "direction "
-                  << direction << "\n";
-        return;
-    }
-    if (!interface)
-    {
-        std::cout << "trying to set uninitialized interface\n";
-        return;
-    }
-    interface->set_property(property, assert);
-}
-
 void HwmonTempSensor::set_initial_properties(
     std::shared_ptr<sdbusplus::asio::connection> &conn)
 {
     // todo, get max and min from configuration
-    sensor_interface->register_property("MaxValue", max_value);
-    sensor_interface->register_property("MinValue", min_value);
-    sensor_interface->register_property("Value", value);
+    sensorInterface->register_property("MaxValue", max_value);
+    sensorInterface->register_property("MinValue", min_value);
+    sensorInterface->register_property("Value", value);
 
     for (auto &threshold : thresholds)
     {
@@ -239,7 +169,7 @@
         std::string alarm;
         if (threshold.level == thresholds::Level::CRITICAL)
         {
-            iface = threshold_interface_critical;
+            iface = thresholdInterfaceCritical;
             if (threshold.direction == thresholds::Direction::HIGH)
             {
                 level = "CriticalHigh";
@@ -253,7 +183,7 @@
         }
         else if (threshold.level == thresholds::Level::WARNING)
         {
-            iface = threshold_interface_warning;
+            iface = thresholdInterfaceWarning;
             if (threshold.direction == thresholds::Direction::HIGH)
             {
                 level = "WarningHigh";
@@ -286,18 +216,16 @@
             });
         iface->register_property(alarm, false);
     }
-    if (!sensor_interface->initialize())
+    if (!sensorInterface->initialize())
     {
         std::cerr << "error initializing value interface\n";
     }
-    if (threshold_interface_warning &&
-        !threshold_interface_warning->initialize())
+    if (thresholdInterfaceWarning && !thresholdInterfaceWarning->initialize())
     {
         std::cerr << "error initializing warning threshold interface\n";
     }
 
-    if (threshold_interface_critical &&
-        !threshold_interface_critical->initialize())
+    if (thresholdInterfaceCritical && !thresholdInterfaceCritical->initialize())
     {
         std::cerr << "error initializing critical threshold interface\n";
     }
diff --git a/sensors/src/TachSensor.cpp b/sensors/src/TachSensor.cpp
index 91f0545..10d94f2 100644
--- a/sensors/src/TachSensor.cpp
+++ b/sensors/src/TachSensor.cpp
@@ -36,27 +36,28 @@
                        boost::asio::io_service &io, const std::string &fanName,
                        std::vector<thresholds::Threshold> &&_thresholds,
                        const std::string &sensorConfiguration) :
-    path(path),
-    objServer(objectServer), dbusConnection(conn),
+    Sensor(),
+    path(path), objServer(objectServer), dbusConnection(conn),
     name(boost::replace_all_copy(fanName, " ", "_")),
-    configuration(sensorConfiguration), thresholds(std::move(_thresholds)),
-    sensor_interface(objectServer.add_interface(
-        "/xyz/openbmc_project/sensors/fan_tach/" + name,
-        "xyz.openbmc_project.Sensor.Value")),
-    input_dev(io, open(path.c_str(), O_RDONLY)), wait_timer(io),
-    value(std::numeric_limits<double>::quiet_NaN()), err_count(0),
+    configuration(sensorConfiguration),
+    input_dev(io, open(path.c_str(), O_RDONLY)), wait_timer(io), err_count(0),
     // todo, get these from config
     max_value(25000), min_value(0)
 {
+    thresholds = std::move(_thresholds);
+    sensorInterface = objectServer.add_interface(
+        "/xyz/openbmc_project/sensors/fan_tach/" + name,
+        "xyz.openbmc_project.Sensor.Value");
+
     if (thresholds::HasWarningInterface(thresholds))
     {
-        threshold_interface_warning = objectServer.add_interface(
+        thresholdInterfaceWarning = objectServer.add_interface(
             "/xyz/openbmc_project/sensors/fan_tach/" + name,
             "xyz.openbmc_project.Sensor.Threshold.Warning");
     }
     if (thresholds::HasCriticalInterface(thresholds))
     {
-        threshold_interface_critical = objectServer.add_interface(
+        thresholdInterfaceCritical = objectServer.add_interface(
             "/xyz/openbmc_project/sensors/fan_tach/" + name,
             "xyz.openbmc_project.Sensor.Threshold.Critical");
     }
@@ -70,9 +71,9 @@
     // close the input dev to cancel async operations
     input_dev.close();
     wait_timer.cancel();
-    objServer.remove_interface(threshold_interface_warning);
-    objServer.remove_interface(threshold_interface_critical);
-    objServer.remove_interface(sensor_interface);
+    objServer.remove_interface(thresholdInterfaceWarning);
+    objServer.remove_interface(thresholdInterfaceCritical);
+    objServer.remove_interface(sensorInterface);
 }
 
 void TachSensor::setup_read(void)
@@ -127,7 +128,7 @@
         else
         {
             err_count = 0; // check power again in 10 cycles
-            sensor_interface->set_property(
+            sensorInterface->set_property(
                 "Value", std::numeric_limits<double>::quiet_NaN());
         }
     }
@@ -151,92 +152,23 @@
 
 void TachSensor::check_thresholds(void)
 {
-    if (thresholds.empty())
-        return;
-    for (auto &threshold : thresholds)
-    {
-        if (threshold.direction == thresholds::Direction::HIGH)
-        {
-            if (value > threshold.value)
-            {
-                assert_thresholds(threshold.level, threshold.direction, true);
-            }
-            else
-            {
-                assert_thresholds(threshold.level, threshold.direction, false);
-            }
-        }
-        else
-        {
-            if (value < threshold.value)
-            {
-                assert_thresholds(threshold.level, threshold.direction, true);
-            }
-            else
-            {
-                assert_thresholds(threshold.level, threshold.direction, false);
-            }
-        }
-    }
+    thresholds::checkThresholds(this);
 }
 
 void TachSensor::update_value(const double &new_value)
 {
-    sensor_interface->set_property("Value", new_value);
+    sensorInterface->set_property("Value", new_value);
     value = new_value;
     check_thresholds();
 }
 
-void TachSensor::assert_thresholds(thresholds::Level level,
-                                   thresholds::Direction direction, bool assert)
-{
-    std::string property;
-    std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
-    if (level == thresholds::Level::WARNING &&
-        direction == thresholds::Direction::HIGH)
-    {
-        property = "WarningAlarmHigh";
-        interface = threshold_interface_warning;
-    }
-    else if (level == thresholds::Level::WARNING &&
-             direction == thresholds::Direction::LOW)
-    {
-        property = "WarningAlarmLow";
-        interface = threshold_interface_warning;
-    }
-    else if (level == thresholds::Level::CRITICAL &&
-             direction == thresholds::Direction::HIGH)
-    {
-        property = "CriticalAlarmHigh";
-        interface = threshold_interface_critical;
-    }
-    else if (level == thresholds::Level::CRITICAL &&
-             direction == thresholds::Direction::LOW)
-    {
-        property = "CriticalAlarmLow";
-        interface = threshold_interface_critical;
-    }
-    else
-    {
-        std::cerr << "Unknown threshold, level " << level << "direction "
-                  << direction << "\n";
-        return;
-    }
-    if (!interface)
-    {
-        std::cout << "trying to set uninitialized interface\n";
-        return;
-    }
-    interface->set_property(property, assert);
-}
-
 void TachSensor::set_initial_properties(
     std::shared_ptr<sdbusplus::asio::connection> &conn)
 {
     // todo, get max and min from configuration
-    sensor_interface->register_property("MaxValue", max_value);
-    sensor_interface->register_property("MinValue", min_value);
-    sensor_interface->register_property("Value", value);
+    sensorInterface->register_property("MaxValue", max_value);
+    sensorInterface->register_property("MinValue", min_value);
+    sensorInterface->register_property("Value", value);
 
     for (auto &threshold : thresholds)
     {
@@ -245,7 +177,7 @@
         std::string alarm;
         if (threshold.level == thresholds::Level::CRITICAL)
         {
-            iface = threshold_interface_critical;
+            iface = thresholdInterfaceCritical;
             if (threshold.direction == thresholds::Direction::HIGH)
             {
                 level = "CriticalHigh";
@@ -259,7 +191,7 @@
         }
         else if (threshold.level == thresholds::Level::WARNING)
         {
-            iface = threshold_interface_warning;
+            iface = thresholdInterfaceWarning;
             if (threshold.direction == thresholds::Direction::HIGH)
             {
                 level = "WarningHigh";
@@ -294,18 +226,16 @@
             });
         iface->register_property(alarm, false);
     }
-    if (!sensor_interface->initialize())
+    if (!sensorInterface->initialize())
     {
         std::cerr << "error initializing value interface\n";
     }
-    if (threshold_interface_warning &&
-        !threshold_interface_warning->initialize())
+    if (thresholdInterfaceWarning && !thresholdInterfaceWarning->initialize())
     {
         std::cerr << "error initializing warning threshold interface\n";
     }
 
-    if (threshold_interface_critical &&
-        !threshold_interface_critical->initialize())
+    if (thresholdInterfaceCritical && !thresholdInterfaceCritical->initialize())
     {
         std::cerr << "error initializing critical threshold interface\n";
     }
diff --git a/sensors/src/Thresholds.cpp b/sensors/src/Thresholds.cpp
index d31f487..b792a9b 100644
--- a/sensors/src/Thresholds.cpp
+++ b/sensors/src/Thresholds.cpp
@@ -4,6 +4,7 @@
 #include <boost/lexical_cast.hpp>
 #include <fstream>
 #include <iostream>
+#include <sensor.hpp>
 
 static constexpr bool DEBUG = false;
 constexpr size_t MAX_THRESHOLDS = 4;
@@ -162,6 +163,91 @@
     }
 }
 
+void checkThresholds(Sensor *sensor)
+{
+
+    if (sensor->thresholds.empty())
+    {
+        return;
+    }
+    for (auto &threshold : sensor->thresholds)
+    {
+        if (threshold.direction == thresholds::Direction::HIGH)
+        {
+            if (sensor->value > threshold.value && !threshold.asserted)
+            {
+                assertThresholds(sensor, threshold.level, threshold.direction,
+                                 true);
+                threshold.asserted = true;
+            }
+            else if (sensor->value <= threshold.value && threshold.asserted)
+            {
+                assertThresholds(sensor, threshold.level, threshold.direction,
+                                 false);
+                threshold.asserted = false;
+            }
+        }
+        else
+        {
+            if (sensor->value < threshold.value && !threshold.asserted)
+            {
+                assertThresholds(sensor, threshold.level, threshold.direction,
+                                 true);
+                threshold.asserted = true;
+            }
+            else if (sensor->value >= threshold.value && threshold.asserted)
+            {
+                assertThresholds(sensor, threshold.level, threshold.direction,
+                                 false);
+                threshold.asserted = false;
+            }
+        }
+    }
+}
+
+void assertThresholds(Sensor *sensor, thresholds::Level level,
+                      thresholds::Direction direction, bool assert)
+{
+    std::string property;
+    std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
+    if (level == thresholds::Level::WARNING &&
+        direction == thresholds::Direction::HIGH)
+    {
+        property = "WarningAlarmHigh";
+        interface = sensor->thresholdInterfaceWarning;
+    }
+    else if (level == thresholds::Level::WARNING &&
+             direction == thresholds::Direction::LOW)
+    {
+        property = "WarningAlarmLow";
+        interface = sensor->thresholdInterfaceWarning;
+    }
+    else if (level == thresholds::Level::CRITICAL &&
+             direction == thresholds::Direction::HIGH)
+    {
+        property = "CriticalAlarmHigh";
+        interface = sensor->thresholdInterfaceCritical;
+    }
+    else if (level == thresholds::Level::CRITICAL &&
+             direction == thresholds::Direction::LOW)
+    {
+        property = "CriticalAlarmLow";
+        interface = sensor->thresholdInterfaceCritical;
+    }
+    else
+    {
+        std::cerr << "Unknown threshold, level " << level << "direction "
+                  << direction << "\n";
+        return;
+    }
+    if (!interface)
+    {
+        std::cout << "trying to set uninitialized interface\n";
+        return;
+    }
+    interface->set_property(property, assert);
+}
+
 static constexpr std::array<const char *, 4> ATTR_TYPES = {"lcrit", "min",
                                                            "max", "crit"};