Add PSU FRU to Redfish

Add PSU FRU to Redfish chassis or baseboard.

Tested:
Check redfish
https://BMC_IP/redfish/v1/Chassis/WC_Baseboard/Power
Page will show:
"PowerSupplies": [
    {
        "@odata.id": "/redfish/v1/Chassis/WC_Baseboard/Power#/PowerSupplies/0",
        "Manufacturer": "SOLUM CO., LTD.                  ",
        "MemberId": "SOLUM_CO_IS162F22_PSU1",
        "Model": "IS162F22",
        "Name": "SOLUM CO IS162F22 PSU1",
        "PartNumber": "G36234-014",
        "PowerInputWatts": 0.0,
        "PowerOutputWatts": 0.0,
        "SerialNumber": "PSSF162202ACNS1622A4BJCB0259",
        "Status": {
            "Health": "OK",
            "State": "Enabled"
        }
    },
    {
        "@odata.id": "/redfish/v1/Chassis/WC_Baseboard/Power#/PowerSupplies/1",
        "Manufacturer": "SOLUM CO., LTD.                  ",
        "MemberId": "SOLUM_CO_IS162F22_PSU2",
        "Model": "IS162F22",
        "Name": "SOLUM CO IS162F22 PSU2",
        "PartNumber": "G36234-013",
        "PowerInputWatts": 152.75,
        "PowerOutputWatts": 135.75,
        "SerialNumber": "PSSF162202ACNS1622A4BJ890333",
        "Status": {
            "Health": "OK",
            "State": "Enabled"
        }
    }
],

Signed-off-by: Cheng C Yang <cheng.c.yang@linux.intel.com>
Change-Id: I1d104b5a3090cdaa9cea22529150569ebfc24730
diff --git a/include/Utils.hpp b/include/Utils.hpp
index 85b0665..4fdbac7 100644
--- a/include/Utils.hpp
+++ b/include/Utils.hpp
@@ -142,3 +142,8 @@
         val = PowerState::always;
     }
 }
+
+void createInventoryAssoc(
+    std::shared_ptr<sdbusplus::asio::connection> conn,
+    std::shared_ptr<sdbusplus::asio::dbus_interface> association,
+    const std::string& path);
diff --git a/src/PSUSensor.cpp b/src/PSUSensor.cpp
index 58dee54..015a367 100644
--- a/src/PSUSensor.cpp
+++ b/src/PSUSensor.cpp
@@ -57,10 +57,12 @@
         thresholdInterfaceCritical = objectServer.add_interface(
             dbusPath, "xyz.openbmc_project.Sensor.Threshold.Critical");
     }
+    setInitialProperties(conn);
+
     association =
         objectServer.add_interface(dbusPath, "org.openbmc.Associations");
 
-    setInitialProperties(conn);
+    createInventoryAssoc(conn, association, configurationPath);
     setupRead();
 }
 
diff --git a/src/Utils.cpp b/src/Utils.cpp
index f1a70b5..a9c2398 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -258,3 +258,49 @@
         association->initialize();
     }
 }
+
+void setInventoryAssociation(
+    std::shared_ptr<sdbusplus::asio::dbus_interface> association,
+    const std::string& path, const std::string& chassisPath)
+{
+    if (association)
+    {
+        std::filesystem::path p(path);
+
+        std::vector<Association> associations;
+        associations.push_back(
+            Association("inventory", "sensors", p.parent_path().string()));
+        associations.push_back(
+            Association("chassis", "all_sensors", chassisPath));
+        association->register_property("associations", associations);
+        association->initialize();
+    }
+}
+
+void createInventoryAssoc(
+    std::shared_ptr<sdbusplus::asio::connection> conn,
+    std::shared_ptr<sdbusplus::asio::dbus_interface> association,
+    const std::string& path)
+{
+    if (!association)
+    {
+        return;
+    }
+    conn->async_method_call(
+        [association, path](const boost::system::error_code ec,
+                            const std::vector<std::string>& ret) {
+            if (ec)
+            {
+                std::cerr << "Error calling mapper\n";
+                return;
+            }
+            for (const auto& object : ret)
+            {
+                setInventoryAssociation(association, path, object);
+            }
+        },
+        mapper::busName, mapper::path, mapper::interface, "GetSubTreePaths",
+        "/xyz/openbmc_project/inventory/system", 2,
+        std::array<std::string, 1>{
+            "xyz.openbmc_project.Inventory.Item.System"});
+}