Add Unit property to dbus interfaces

Previously, the lack of the Unit property on the Value interfaces
provided by dbus-sensors meant that readings from its sensors weren't
displayed in phosphor-webui/webui-vue.  Here it's added as an extra
parameter to setInitialProperties, allowing sensors that handle multiple
types of data (e.g. IpmbSensor, PSUSensor) to determine the appropriate
string to pass once they've had time to determine that.

Tested: PSUSensor, ADCSensor, CPUSensor, TachSensor, and HwmonTempSensor
all have an appropriate Unit property available on dbus, and are
displayed in webui-vue.

Signed-off-by: Zev Weiss <zev@bewilderbeest.net>
Change-Id: I5e6df74cc42d9fb84852c5bf3ea5d3b383a16cdc
diff --git a/include/IpmbSensor.hpp b/include/IpmbSensor.hpp
index ff15fa6..4effd18 100644
--- a/include/IpmbSensor.hpp
+++ b/include/IpmbSensor.hpp
@@ -87,6 +87,7 @@
     void checkThresholds(void) override;
     void read(void);
     void init(void);
+    std::string getSubTypeUnits(void);
     void loadDefaults(void);
     void runInitCmd(void);
     bool processReading(const std::vector<uint8_t>& data, double& resp);
diff --git a/include/PSUSensor.hpp b/include/PSUSensor.hpp
index fd69c5a..e309aeb 100644
--- a/include/PSUSensor.hpp
+++ b/include/PSUSensor.hpp
@@ -19,7 +19,7 @@
               boost::asio::io_service& io, const std::string& sensorName,
               std::vector<thresholds::Threshold>&& thresholds,
               const std::string& sensorConfiguration,
-              std::string& sensorTypeName, unsigned int factor, double max,
+              const std::string& sensorUnits, unsigned int factor, double max,
               double min, const std::string& label, size_t tSize);
     ~PSUSensor() override;
     void setupRead(void);
diff --git a/include/PwmSensor.hpp b/include/PwmSensor.hpp
index 1f8a467..d78b8e9 100644
--- a/include/PwmSensor.hpp
+++ b/include/PwmSensor.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <sdbusplus/asio/object_server.hpp>
+#include <sensor.hpp>
 
 #include <memory>
 #include <string>
diff --git a/include/SensorPaths.hpp b/include/SensorPaths.hpp
index e8ed8fa..023d615 100644
--- a/include/SensorPaths.hpp
+++ b/include/SensorPaths.hpp
@@ -11,6 +11,21 @@
 // with
 // phosphor-dbus-interfaces/blob/master/xyz/openbmc_project/Sensor/Value.interface.yaml#L35
 
+constexpr const char* unitDegreesC =
+    "xyz.openbmc_project.Sensor.Value.Unit.DegreesC";
+constexpr const char* unitRPMs = "xyz.openbmc_project.Sensor.Value.Unit.RPMS";
+constexpr const char* unitVolts = "xyz.openbmc_project.Sensor.Value.Unit.Volts";
+constexpr const char* unitMeters =
+    "xyz.openbmc_project.Sensor.Value.Unit.Meters";
+constexpr const char* unitAmperes =
+    "xyz.openbmc_project.Sensor.Value.Unit.Amperes";
+constexpr const char* unitWatts = "xyz.openbmc_project.Sensor.Value.Unit.Watts";
+constexpr const char* unitJoules =
+    "xyz.openbmc_project.Sensor.Value.Unit.Joules";
+constexpr const char* unitPercent =
+    "xyz.openbmc_project.Sensor.Value.Unit.Percent";
+constexpr const char* unitCFM = "xyz.openbmc_project.Sensor.Value.Unit.CFM";
+
 std::string getPathForUnits(const std::string& units);
 
 std::string escapePathForDbus(const std::string& name);
diff --git a/include/sensor.hpp b/include/sensor.hpp
index dc91fc1..d1fb22e 100644
--- a/include/sensor.hpp
+++ b/include/sensor.hpp
@@ -194,6 +194,7 @@
 
     void
         setInitialProperties(std::shared_ptr<sdbusplus::asio::connection>& conn,
+                             const std::string& unit,
                              const std::string& label = std::string(),
                              size_t thresholdSize = 0)
     {
@@ -204,6 +205,7 @@
 
         createAssociation(association, configurationPath);
 
+        sensorInterface->register_property("Unit", unit);
         sensorInterface->register_property("MaxValue", maxValue);
         sensorInterface->register_property("MinValue", minValue);
         sensorInterface->register_property(
diff --git a/src/ADCSensor.cpp b/src/ADCSensor.cpp
index 57a6434..c858df7 100644
--- a/src/ADCSensor.cpp
+++ b/src/ADCSensor.cpp
@@ -80,7 +80,7 @@
     }
     association = objectServer.add_interface(
         "/xyz/openbmc_project/sensors/voltage/" + name, association::interface);
-    setInitialProperties(conn);
+    setInitialProperties(conn, sensor_paths::unitVolts);
 }
 
 ADCSensor::~ADCSensor()
diff --git a/src/CPUSensor.cpp b/src/CPUSensor.cpp
index 939bbc2..40b86d1 100644
--- a/src/CPUSensor.cpp
+++ b/src/CPUSensor.cpp
@@ -56,9 +56,11 @@
         {
             auto& [type, nr, item] = *fileParts;
             std::string interfacePath;
+            const char* units;
             if (type.compare("power") == 0)
             {
                 interfacePath = "/xyz/openbmc_project/sensors/power/" + name;
+                units = sensor_paths::unitWatts;
                 minValue = 0;
                 maxValue = 511;
             }
@@ -66,6 +68,7 @@
             {
                 interfacePath =
                     "/xyz/openbmc_project/sensors/temperature/" + name;
+                units = sensor_paths::unitDegreesC;
                 minValue = -128;
                 maxValue = 127;
             }
@@ -87,7 +90,7 @@
             association = objectServer.add_interface(interfacePath,
                                                      association::interface);
 
-            setInitialProperties(conn);
+            setInitialProperties(conn, units);
         }
     }
 
diff --git a/src/ExitAirTempSensor.cpp b/src/ExitAirTempSensor.cpp
index 82b75eb..feb37ee 100644
--- a/src/ExitAirTempSensor.cpp
+++ b/src/ExitAirTempSensor.cpp
@@ -189,7 +189,7 @@
     association = objectServer.add_interface(
         "/xyz/openbmc_project/sensors/cfm/" + name, association::interface);
 
-    setInitialProperties(conn);
+    setInitialProperties(conn, sensor_paths::unitCFM);
 
     pwmLimitIface =
         objectServer.add_interface("/xyz/openbmc_project/control/pwm_limit",
@@ -536,7 +536,7 @@
     association = objectServer.add_interface(
         "/xyz/openbmc_project/sensors/temperature/" + name,
         association::interface);
-    setInitialProperties(conn);
+    setInitialProperties(conn, sensor_paths::unitDegreesC);
 }
 
 ExitAirTempSensor::~ExitAirTempSensor()
diff --git a/src/ExternalSensor.cpp b/src/ExternalSensor.cpp
index 3aba626..91f488b 100644
--- a/src/ExternalSensor.cpp
+++ b/src/ExternalSensor.cpp
@@ -70,7 +70,7 @@
 
     association =
         objectServer.add_interface(objectPath, association::interface);
-    setInitialProperties(conn);
+    setInitialProperties(conn, sensorUnits);
 
     if constexpr (debug)
     {
diff --git a/src/HwmonTempSensor.cpp b/src/HwmonTempSensor.cpp
index 41fc357..72b20d0 100644
--- a/src/HwmonTempSensor.cpp
+++ b/src/HwmonTempSensor.cpp
@@ -70,7 +70,7 @@
     association = objectServer.add_interface(
         "/xyz/openbmc_project/sensors/temperature/" + name,
         association::interface);
-    setInitialProperties(conn);
+    setInitialProperties(conn, sensor_paths::unitDegreesC);
 }
 
 HwmonTempSensor::~HwmonTempSensor()
diff --git a/src/IpmbSensor.cpp b/src/IpmbSensor.cpp
index 2d40dc3..503a256 100644
--- a/src/IpmbSensor.cpp
+++ b/src/IpmbSensor.cpp
@@ -98,10 +98,29 @@
     objectServer.remove_interface(association);
 }
 
+std::string IpmbSensor::getSubTypeUnits(void)
+{
+    switch (subType)
+    {
+        case IpmbSubType::temp:
+            return sensor_paths::unitDegreesC;
+        case IpmbSubType::curr:
+            return sensor_paths::unitAmperes;
+        case IpmbSubType::power:
+            return sensor_paths::unitWatts;
+        case IpmbSubType::volt:
+            return sensor_paths::unitVolts;
+        case IpmbSubType::util:
+            return sensor_paths::unitPercent;
+        default:
+            throw std::runtime_error("Invalid sensor type");
+    }
+}
+
 void IpmbSensor::init(void)
 {
     loadDefaults();
-    setInitialProperties(dbusConnection);
+    setInitialProperties(dbusConnection, getSubTypeUnits());
     if (initCommand)
     {
         runInitCmd();
diff --git a/src/MCUTempSensor.cpp b/src/MCUTempSensor.cpp
index f637932..6a64c16 100644
--- a/src/MCUTempSensor.cpp
+++ b/src/MCUTempSensor.cpp
@@ -95,7 +95,7 @@
 
 void MCUTempSensor::init(void)
 {
-    setInitialProperties(dbusConnection);
+    setInitialProperties(dbusConnection, sensor_paths::unitDegreesC);
     read();
 }
 
diff --git a/src/NVMeSensor.cpp b/src/NVMeSensor.cpp
index 1c78354..24f3fd4 100644
--- a/src/NVMeSensor.cpp
+++ b/src/NVMeSensor.cpp
@@ -462,7 +462,7 @@
         "/xyz/openbmc_project/sensors/temperature/" + name,
         association::interface);
 
-    setInitialProperties(conn);
+    setInitialProperties(conn, sensor_paths::unitDegreesC);
 }
 
 NVMeSensor::~NVMeSensor()
diff --git a/src/PSUSensor.cpp b/src/PSUSensor.cpp
index e292863..a528819 100644
--- a/src/PSUSensor.cpp
+++ b/src/PSUSensor.cpp
@@ -41,7 +41,7 @@
                      boost::asio::io_service& io, const std::string& sensorName,
                      std::vector<thresholds::Threshold>&& thresholdsIn,
                      const std::string& sensorConfiguration,
-                     std::string& sensorTypeName, unsigned int factor,
+                     const std::string& sensorUnits, unsigned int factor,
                      double max, double min, const std::string& label,
                      size_t tSize) :
     Sensor(boost::replace_all_copy(sensorName, " ", "_"),
@@ -51,13 +51,14 @@
     inputDev(io), waitTimer(io), path(path), pathRatedMax(""), pathRatedMin(""),
     sensorFactor(factor), minMaxReadCounter(0)
 {
+    std::string unitPath = sensor_paths::getPathForUnits(sensorUnits);
     if constexpr (debug)
     {
         std::cerr << "Constructed sensor: path " << path << " type "
                   << objectType << " config " << sensorConfiguration
-                  << " typename " << sensorTypeName << " factor " << factor
-                  << " min " << min << " max " << max << " name \""
-                  << sensorName << "\"\n";
+                  << " typename " << unitPath << " factor " << factor << " min "
+                  << min << " max " << max << " name \"" << sensorName
+                  << "\"\n";
     }
 
     fd = open(path.c_str(), O_RDONLY);
@@ -68,7 +69,7 @@
     }
     inputDev.assign(fd);
 
-    std::string dbusPath = sensorPathPrefix + sensorTypeName + name;
+    std::string dbusPath = sensorPathPrefix + unitPath + "/" + name;
 
     sensorInterface = objectServer.add_interface(
         dbusPath, "xyz.openbmc_project.Sensor.Value");
@@ -89,11 +90,11 @@
     // register and initialize "Associations" property.
     if (label.empty() || tSize == thresholds.size())
     {
-        setInitialProperties(conn);
+        setInitialProperties(conn, sensorUnits);
     }
     else
     {
-        setInitialProperties(conn, label, tSize);
+        setInitialProperties(conn, sensorUnits, label, tSize);
     }
 
     association = objectServer.add_interface(dbusPath, association::interface);
diff --git a/src/PSUSensorMain.cpp b/src/PSUSensorMain.cpp
index baf2bd1..6595db9 100644
--- a/src/PSUSensorMain.cpp
+++ b/src/PSUSensorMain.cpp
@@ -774,8 +774,8 @@
                           << sensorNameSubStr << "\n";
             }
 
-            auto findSensorType = sensorTable.find(sensorNameSubStr);
-            if (findSensorType == sensorTable.end())
+            auto findSensorUnit = sensorTable.find(sensorNameSubStr);
+            if (findSensorUnit == sensorTable.end())
             {
                 std::cerr << sensorNameSubStr
                           << " is not a recognized sensor type\n";
@@ -821,7 +821,7 @@
             sensors[sensorName] = std::make_shared<PSUSensor>(
                 sensorPathStr, sensorType, objectServer, dbusConnection, io,
                 sensorName, std::move(sensorThresholds), *interfacePath,
-                findSensorType->second, factor, psuProperty->maxReading,
+                findSensorUnit->second, factor, psuProperty->maxReading,
                 psuProperty->minReading, labelHead, thresholdConfSize);
             sensors[sensorName]->setupRead();
             ++numCreated;
@@ -864,11 +864,11 @@
 
 void propertyInitialize(void)
 {
-    sensorTable = {{"power", "power/"},
-                   {"curr", "current/"},
-                   {"temp", "temperature/"},
-                   {"in", "voltage/"},
-                   {"fan", "fan_tach/"}};
+    sensorTable = {{"power", sensor_paths::unitWatts},
+                   {"curr", sensor_paths::unitAmperes},
+                   {"temp", sensor_paths::unitDegreesC},
+                   {"in", sensor_paths::unitVolts},
+                   {"fan", sensor_paths::unitRPMs}};
 
     labelMatch = {{"pin", PSUProperty("Input Power", 3000, 0, 6)},
                   {"pout1", PSUProperty("Output Power", 3000, 0, 6)},
diff --git a/src/PwmSensor.cpp b/src/PwmSensor.cpp
index bd9c9d6..f76ea50 100644
--- a/src/PwmSensor.cpp
+++ b/src/PwmSensor.cpp
@@ -107,6 +107,7 @@
     // pwm sensor interface is in percent
     sensorInterface->register_property("MaxValue", static_cast<int64_t>(100));
     sensorInterface->register_property("MinValue", static_cast<int64_t>(0));
+    sensorInterface->register_property("Unit", sensor_paths::unitPercent);
 
     controlInterface = objectServer.add_interface(
         "/xyz/openbmc_project/control/fanpwm/" + name,
diff --git a/src/SensorPaths.cpp b/src/SensorPaths.cpp
index f10e60b..b0cea9c 100644
--- a/src/SensorPaths.cpp
+++ b/src/SensorPaths.cpp
@@ -1,3 +1,5 @@
+#include <SensorPaths.hpp>
+
 #include <cstring>
 #include <regex>
 #include <string>
@@ -11,35 +13,35 @@
 
 std::string getPathForUnits(const std::string& units)
 {
-    if (units == "DegreesC")
+    if (units == "DegreesC" || units == unitDegreesC)
     {
         return "temperature";
     }
-    if (units == "RPMS")
+    if (units == "RPMS" || units == unitRPMs)
     {
         return "fan_tach";
     }
-    if (units == "Volts")
+    if (units == "Volts" || units == unitVolts)
     {
         return "voltage";
     }
-    if (units == "Meters")
+    if (units == "Meters" || units == unitMeters)
     {
         return "altitude";
     }
-    if (units == "Amperes")
+    if (units == "Amperes" || units == unitAmperes)
     {
         return "current";
     }
-    if (units == "Watts")
+    if (units == "Watts" || units == unitWatts)
     {
         return "power";
     }
-    if (units == "Joules")
+    if (units == "Joules" || units == unitJoules)
     {
         return "energy";
     }
-    if (units == "Percent")
+    if (units == "Percent" || units == unitPercent)
     {
         return "Utilization";
     }
diff --git a/src/TachSensor.cpp b/src/TachSensor.cpp
index 1ec979f..b3c955c 100644
--- a/src/TachSensor.cpp
+++ b/src/TachSensor.cpp
@@ -97,7 +97,7 @@
                  "/xyz/openbmc_project/sensors/fan_tach/" + name}});
         itemAssoc->initialize();
     }
-    setInitialProperties(conn);
+    setInitialProperties(conn, sensor_paths::unitRPMs);
     setupRead();
 }