pldm_events: Implement support for state sensorEvents

PLDM supports platform event message by which events can be generated
by a PLDM entity and can be processed by event receiver like BMC. This
patch adds support for remote state sensors which sends PlatformEventMessage
command with sensorEvent type. The sensor is mapped to a D-Bus property
and the eventState is mapped to a D-Bus property value.

Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
Change-Id: I50dea23eccbdf29ad1b4cf2c9ab5700d74c12c68
diff --git a/libpldmresponder/event_parser.cpp b/libpldmresponder/event_parser.cpp
new file mode 100644
index 0000000..0a0000c
--- /dev/null
+++ b/libpldmresponder/event_parser.cpp
@@ -0,0 +1,162 @@
+#include "event_parser.hpp"

+

+#include <filesystem>

+#include <fstream>

+#include <iostream>

+#include <set>

+#include <xyz/openbmc_project/Common/error.hpp>

+

+namespace pldm::responder::events

+{

+

+namespace fs = std::filesystem;

+using InternalFailure =

+    sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;

+

+const Json emptyJson{};

+const std::vector<Json> emptyJsonList{};

+const std::vector<std::string> emptyStringVec{};

+

+constexpr auto eventStateSensorJson = "event_state_sensor.json";

+

+const std::set<std::string_view> supportedDbusPropertyTypes = {

+    "bool",     "uint8_t", "int16_t",  "uint16_t", "int32_t",

+    "uint32_t", "int64_t", "uint64_t", "double",   "string"};

+

+StateSensorHandler::StateSensorHandler(const std::string& dirPath)

+{

+    fs::path dir(dirPath);

+    if (!fs::exists(dir) || fs::is_empty(dir))

+    {

+        std::cerr << "Event config directory does not exist or empty, DIR="

+                  << dirPath << "\n";

+        return;

+    }

+

+    fs::path filePath = dir / eventStateSensorJson;

+    if (!fs::exists(filePath))

+    {

+        std::cerr << "Event state sensor JSON does not exist, PATH=" << filePath

+                  << "\n";

+        throw InternalFailure();

+    }

+

+    std::ifstream jsonFile(filePath);

+

+    auto data = Json::parse(jsonFile, nullptr, false);

+    if (data.is_discarded())

+    {

+        std::cerr << "Parsing Event state sensor JSON file failed, FILE="

+                  << filePath;

+        throw InternalFailure();

+    }

+

+    auto entries = data.value("entries", emptyJsonList);

+    for (const auto& entry : entries)

+    {

+        StateSensorEntry stateSensorEntry{};

+        stateSensorEntry.containerId =

+            static_cast<uint16_t>(entry.value("containerID", 0));

+        stateSensorEntry.entityType =

+            static_cast<uint16_t>(entry.value("entityType", 0));

+        stateSensorEntry.entityInstance =

+            static_cast<uint16_t>(entry.value("entityInstance", 0));

+        stateSensorEntry.sensorOffset =

+            static_cast<uint8_t>(entry.value("sensorOffset", 0));

+

+        pldm::utils::DBusMapping dbusInfo{};

+

+        auto dbus = entry.value("dbus", emptyJson);

+        dbusInfo.objectPath = dbus.value("object_path", "");

+        dbusInfo.interface = dbus.value("interface", "");

+        dbusInfo.propertyName = dbus.value("property_name", "");

+        dbusInfo.propertyType = dbus.value("property_type", "");

+        if (dbusInfo.objectPath.empty() || dbusInfo.interface.empty() ||

+            dbusInfo.propertyName.empty() ||

+            (supportedDbusPropertyTypes.find(dbusInfo.propertyType) ==

+             supportedDbusPropertyTypes.end()))

+        {

+            std::cerr << "Invalid dbus config,"

+                      << " OBJPATH=" << dbusInfo.objectPath << " INTERFACE="

+                      << dbusInfo.interface << " PROPERTY_NAME="

+                      << dbusInfo.propertyName

+                      << " PROPERTY_TYPE=" << dbusInfo.propertyType << "\n";

+            continue;

+        }

+

+        auto eventStates = entry.value("event_states", emptyJsonList);

+        auto propertyValues = dbus.value("property_values", emptyJsonList);

+        if ((eventStates.size() == 0) || (propertyValues.size() == 0) ||

+            (eventStates.size() != propertyValues.size()))

+        {

+            std::cerr << "Invalid event state JSON config,"

+                      << " EVENT_STATE_SIZE=" << eventStates.size()

+                      << " PROPERTY_VALUE_SIZE=" << propertyValues.size()

+                      << "\n";

+            continue;

+        }

+

+        auto eventStateMap = mapStateToDBusVal(eventStates, propertyValues,

+                                               dbusInfo.propertyType);

+        eventMap.emplace(

+            stateSensorEntry,

+            std::make_tuple(std::move(dbusInfo), std::move(eventStateMap)));

+    }

+}

+

+StateToDBusValue StateSensorHandler::mapStateToDBusVal(

+    const Json& eventStates, const Json& propertyValues, std::string_view type)

+{

+    StateToDBusValue eventStateMap{};

+    auto stateIt = eventStates.begin();

+    auto propIt = propertyValues.begin();

+

+    for (; stateIt != eventStates.end(); ++stateIt, ++propIt)

+    {

+        auto propValue = utils::jsonEntryToDbusVal(type, propIt.value());

+        eventStateMap.emplace((*stateIt).get<uint8_t>(), std::move(propValue));

+    }

+

+    return eventStateMap;

+}

+

+int StateSensorHandler::eventAction(const StateSensorEntry& entry,

+                                    pdr::EventState state)

+{

+    try

+    {

+        const auto& [dbusMapping, eventStateMap] = eventMap.at(entry);

+        utils::PropertyValue propValue{};

+        try

+        {

+            propValue = eventStateMap.at(state);

+        }

+        catch (const std::out_of_range& e)

+        {

+            std::cerr << "Invalid event state" << static_cast<unsigned>(state)

+                      << '\n';

+            return PLDM_ERROR_INVALID_DATA;

+        }

+

+        try

+        {

+            pldm::utils::DBusHandler().setDbusProperty(dbusMapping, propValue);

+        }

+        catch (const std::exception& e)

+        {

+            std::cerr << "Error setting property, ERROR=" << e.what()

+                      << " PROPERTY=" << dbusMapping.propertyName

+                      << " INTERFACE=" << dbusMapping.interface << " PATH="

+                      << dbusMapping.objectPath << "\n";

+            return PLDM_ERROR;

+        }

+    }

+    catch (const std::out_of_range& e)

+    {

+        // There is no BMC action for this PLDM event

+        return PLDM_SUCCESS;

+    }

+    return PLDM_SUCCESS;

+}

+

+} // namespace pldm::responder::events
\ No newline at end of file
diff --git a/libpldmresponder/event_parser.hpp b/libpldmresponder/event_parser.hpp
new file mode 100644
index 0000000..1139c71
--- /dev/null
+++ b/libpldmresponder/event_parser.hpp
@@ -0,0 +1,120 @@
+#pragma once

+

+#include "types.hpp"

+#include "utils.hpp"

+

+#include <filesystem>

+#include <map>

+#include <nlohmann/json.hpp>

+#include <string>

+#include <tuple>

+#include <vector>

+

+namespace pldm::responder::events

+{

+

+/** @struct StateSensorEntry

+ *

+ *  StateSensorEntry is a key to uniquely identify a state sensor, so that a

+ *  D-Bus action can be defined for PlatformEventMessage command with

+ *  sensorEvent type. This struct is used as a key in a std::map so implemented

+ *  operator== and operator<.

+ */

+struct StateSensorEntry

+{

+    pdr::ContainerID containerId;

+    pdr::EntityType entityType;

+    pdr::EntityInstance entityInstance;

+    pdr::SensorOffset sensorOffset;

+

+    bool operator==(const StateSensorEntry& e) const

+    {

+        return ((containerId == e.containerId) &&

+                (entityType == e.entityType) &&

+                (entityInstance == e.entityInstance) &&

+                (sensorOffset == e.sensorOffset));

+    }

+

+    bool operator<(const StateSensorEntry& e) const

+    {

+        return (

+            (containerId < e.containerId) ||

+            ((containerId == e.containerId) && (entityType < e.entityType)) ||

+            ((containerId == e.containerId) && (entityType == e.entityType) &&

+             (entityInstance < e.entityInstance)) ||

+            ((containerId == e.containerId) && (entityType == e.entityType) &&

+             (entityInstance == e.entityInstance) &&

+             (sensorOffset < e.sensorOffset)));

+    }

+};

+

+using StateToDBusValue = std::map<pdr::EventState, pldm::utils::PropertyValue>;

+using EventDBusInfo = std::tuple<pldm::utils::DBusMapping, StateToDBusValue>;

+using EventMap = std::map<StateSensorEntry, EventDBusInfo>;

+using Json = nlohmann::json;

+

+/** @class StateSensorHandler

+ *

+ *  @brief Parses the event state sensor configuration JSON file and build

+ *         the lookup data structure, which can map the event state for a

+ *         sensor in the PlatformEventMessage command to a D-Bus property and

+ *         the property value.

+ */

+class StateSensorHandler

+{

+  public:

+    StateSensorHandler() = delete;

+

+    /** @brief Parse the event state sensor configuration JSON file and build

+     *         the lookup data stucture.

+     *

+     *  @param[in] dirPath - directory path which has the config JSONs

+     */

+    explicit StateSensorHandler(const std::string& dirPath);

+    virtual ~StateSensorHandler() = default;

+    StateSensorHandler(const StateSensorHandler&) = default;

+    StateSensorHandler& operator=(const StateSensorHandler&) = default;

+    StateSensorHandler(StateSensorHandler&&) = default;

+    StateSensorHandler& operator=(StateSensorHandler&&) = default;

+

+    /** @brief If the StateSensorEntry and EventState is valid, the D-Bus

+     *         property corresponding to the StateSensorEntry is set based on

+     *         the EventState

+     *

+     *  @param[in] entry - state sensor entry

+     *  @param[in] state - event state

+     *

+     *  @return PLDM completion code

+     */

+    int eventAction(const StateSensorEntry& entry, pdr::EventState state);

+

+    /** @brief Helper API to get D-Bus information for a StateSensorEntry

+     *

+     *  @param[in] entry - state sensor entry

+     *

+     *  @return D-Bus information corresponding to the SensorEntry

+     */

+    const EventDBusInfo& getEventInfo(const StateSensorEntry& entry) const

+    {

+        return eventMap.at(entry);

+    }

+

+  private:

+    EventMap eventMap; //!< a map of StateSensorEntry to D-Bus information

+

+    /** @brief Create a map of EventState to D-Bus property values from

+     *         the information provided in the event state configuration

+     *         JSON

+     *

+     *  @param[in] eventStates - a JSON array of event states

+     *  @param[in] propertyValues - a JSON array of D-Bus property values

+     *  @param[in] type - the type of D-Bus property

+     *

+     *  @return a map of EventState to D-Bus property values

+     */

+    StateToDBusValue mapStateToDBusVal(const Json& eventStates,

+                                       const Json& propertyValues,

+                                       std::string_view type);

+};

+

+} // namespace pldm::responder::events
\ No newline at end of file
diff --git a/libpldmresponder/examples/events/event_state_sensor.json b/libpldmresponder/examples/events/event_state_sensor.json
new file mode 100644
index 0000000..47713b8
--- /dev/null
+++ b/libpldmresponder/examples/events/event_state_sensor.json
@@ -0,0 +1,69 @@
+# Each entry is to uniquely identify a remote state sensor(there are separate

+# entry for each sensor in a composite sensor) and the supported event states.

+# The "dbus" section contains information about the corresponding D-Bus

+# property for the sensor and "property_values" are the D-Bus property values

+# for each corresponding entry in the "event_states"

+{

+    "entries": [

+        {

+            "containerID": 1,

+            "entityType": 64,

+            "entityInstance": 1,

+            "sensorOffset": 0,

+            "event_states": [

+                0,

+                1

+            ],

+            "dbus": {

+                "object_path": "/xyz/abc/def",

+                "interface": "xyz.openbmc_project.example1.value",

+                "property_name": "value1",

+                "property_type": "string",

+                "property_values": [

+                    "xyz.openbmc_project.State.On",

+                    "xyz.openbmc_project.State.Off"

+                ]

+            }

+        },

+        {

+            "containerID": 1,

+            "entityType": 64,

+            "entityInstance": 1,

+            "sensorOffset": 1,

+            "event_states": [

+                2,

+                3

+            ],

+            "dbus": {

+                "object_path": "/xyz/abc/def",

+                "interface": "xyz.openbmc_project.example2.value",

+                "property_name": "value2",

+                "property_type": "uint8_t",

+                "property_values": [

+                    9,

+                    10

+                ]

+            }

+        },

+        {

+            "containerID": 1,

+            "entityType": 67,

+            "entityInstance": 1,

+            "sensorOffset": 0,

+            "event_states": [

+                0,

+                1

+            ],

+            "dbus": {

+                "object_path": "/xyz/abc/ghi",

+                "interface": "xyz.openbmc_project.example3.value",

+                "property_name": "value3",

+                "property_type": "bool",

+                "property_values": [

+                    false,

+                    true

+                ]

+            }

+        }

+    ]

+}

diff --git a/libpldmresponder/meson.build b/libpldmresponder/meson.build
index 0275e94..8231630 100644
--- a/libpldmresponder/meson.build
+++ b/libpldmresponder/meson.build
@@ -20,7 +20,8 @@
   'platform.cpp',
   'fru_parser.cpp',
   'fru.cpp',
-  '../host_pdr_handler.cpp'
+  '../host_pdr_handler.cpp',
+  'event_parser.cpp'
 ]
 
 if get_option('oem-ibm').enabled()
diff --git a/libpldmresponder/platform.hpp b/libpldmresponder/platform.hpp
index 1982031..a21502e 100644
--- a/libpldmresponder/platform.hpp
+++ b/libpldmresponder/platform.hpp
@@ -2,6 +2,7 @@
 
 #include "config.h"
 
+#include "event_parser.hpp"
 #include "handler.hpp"
 #include "host_pdr_handler.hpp"
 #include "libpldmresponder/pdr.hpp"
@@ -53,13 +54,13 @@
 class Handler : public CmdHandler
 {
   public:
-    Handler(const std::string& dir, pldm_pdr* repo,
-            HostPDRHandler* hostPDRHandler,
+    Handler(const std::string& pdrJsonsDir, const std::string& eventsJsonsDir,
+            pldm_pdr* repo, HostPDRHandler* hostPDRHandler,
             const std::optional<EventMap>& addOnHandlersMap = std::nullopt) :
         pdrRepo(repo),
-        hostPDRHandler(hostPDRHandler)
+        hostPDRHandler(hostPDRHandler), stateSensorHandler(eventsJsonsDir)
     {
-        generate(dir, pdrRepo);
+        generate(pdrJsonsDir, pdrRepo);
 
         handlers.emplace(PLDM_GET_PDR,
                          [this](const pldm_msg* request, size_t payloadLength) {
@@ -394,6 +395,7 @@
     uint16_t nextEffecterId{};
     DbusObjMaps dbusObjMaps{};
     HostPDRHandler* hostPDRHandler;
+    events::StateSensorHandler stateSensorHandler;
 };
 
 } // namespace platform
diff --git a/meson.build b/meson.build
index 23c3b72..88fe1d2 100644
--- a/meson.build
+++ b/meson.build
@@ -19,6 +19,7 @@
 conf_data.set_quoted('PDR_JSONS_DIR', '/usr/share/pldm/pdr')
 conf_data.set_quoted('FRU_JSONS_DIR', '/usr/share/pldm/fru')
 conf_data.set_quoted('HOST_JSONS_DIR', '/usr/share/pldm/host')
+conf_data.set_quoted('EVENTS_JSONS_DIR', '/usr/share/pldm/events')
 if get_option('oem-ibm').enabled()
   conf_data.set_quoted('FILE_TABLE_JSON', '/usr/share/pldm/fileTable.json')
   conf_data.set_quoted('LID_PERM_DIR', '/usr/share/host-fw')
diff --git a/pldmd.cpp b/pldmd.cpp
index eb882f4..d1ca6fa 100644
--- a/pldmd.cpp
+++ b/pldmd.cpp
@@ -179,9 +179,10 @@
     Invoker invoker{};
     invoker.registerHandler(PLDM_BASE, std::make_unique<base::Handler>());
     invoker.registerHandler(PLDM_BIOS, std::make_unique<bios::Handler>());
-    invoker.registerHandler(
-        PLDM_PLATFORM, std::make_unique<platform::Handler>(
-                           PDR_JSONS_DIR, pdrRepo.get(), hostPDRHandler.get()));
+    invoker.registerHandler(PLDM_PLATFORM,
+                            std::make_unique<platform::Handler>(
+                                PDR_JSONS_DIR, EVENTS_JSONS_DIR, pdrRepo.get(),
+                                hostPDRHandler.get()));
     invoker.registerHandler(
         PLDM_FRU, std::make_unique<fru::Handler>(FRU_JSONS_DIR, pdrRepo.get(),
                                                  entityTree.get()));
diff --git a/test/event_jsons/good/event_state_sensor.json b/test/event_jsons/good/event_state_sensor.json
new file mode 100644
index 0000000..f10a319
--- /dev/null
+++ b/test/event_jsons/good/event_state_sensor.json
@@ -0,0 +1,66 @@
+{

+    "entries": [

+        {

+            "containerID": 1,

+            "entityType": 64,

+            "entityInstance": 1,

+            "sensorOffset": 0,

+            "event_states": [

+                0,

+                1,

+                2

+            ],

+            "dbus": {

+                "object_path": "/xyz/abc/def",

+                "interface": "xyz.openbmc_project.example1.value",

+                "property_name": "value1",

+                "property_type": "string",

+                "property_values": [

+                    "xyz.openbmc_project.State.Normal",

+                    "xyz.openbmc_project.State.Critical",

+                    "xyz.openbmc_project.State.Fatal"

+                ]

+            }

+        },

+        {

+            "containerID": 1,

+            "entityType": 64,

+            "entityInstance": 1,

+            "sensorOffset": 1,

+            "event_states": [

+                2,

+                3

+            ],

+            "dbus": {

+                "object_path": "/xyz/abc/def",

+                "interface": "xyz.openbmc_project.example2.value",

+                "property_name": "value2",

+                "property_type": "uint8_t",

+                "property_values": [

+                    9,

+                    10

+                ]

+            }

+        },

+        {

+            "containerID": 2,

+            "entityType": 67,

+            "entityInstance": 2,

+            "sensorOffset": 0,

+            "event_states": [

+                0,

+                1

+            ],

+            "dbus": {

+                "object_path": "/xyz/abc/ghi",

+                "interface": "xyz.openbmc_project.example3.value",

+                "property_name": "value3",

+                "property_type": "bool",

+                "property_values": [

+                    false,

+                    true

+                ]

+            }

+        }

+    ]

+}

diff --git a/test/event_jsons/malformed1/event_state.json b/test/event_jsons/malformed1/event_state.json
new file mode 100644
index 0000000..29f9b04
--- /dev/null
+++ b/test/event_jsons/malformed1/event_state.json
@@ -0,0 +1,26 @@
+{

+    "entries": [

+        {

+            "containerID": 1,

+            "entityType": 64,

+            "entityInstance": 1,

+            "sensorOffset": 1,

+            "event_states": [

+                0,

+                1,

+                2

+            ],

+            "dbus": {

+                "object_path": "/xyz/abc/def",

+                "interface": "xyz.openbmc_project.example1.value",

+                "property_name": "value1",

+                "property_type": "string",

+                "property_values": [

+                    "xyz.openbmc_project.State.Normal",

+                    "xyz.openbmc_project.State.Critical",

+                    "xyz.openbmc_project.State.Fatal"

+                ]

+            }

+        }

+    ]

+}

diff --git a/test/event_jsons/malformed2/event_state_sensor.json b/test/event_jsons/malformed2/event_state_sensor.json
new file mode 100644
index 0000000..f7de057
--- /dev/null
+++ b/test/event_jsons/malformed2/event_state_sensor.json
@@ -0,0 +1,26 @@
+{

+    "entries": [

+        {

+            "containerID": 1,

+            "entityType": 64,

+            "entityInstance": 1,

+            "sensorOffset": 1,

+            "event_states": [

+                0,

+                1,

+                2

+            ],

+            "dbus": {

+                "object_path": "/xyz/abc/def",

+                "interface": "xyz.openbmc_project.example1.value",

+                "property_name": "value1",

+                "property_type": "string",

+                "property_values": [

+                    "xyz.openbmc_project.State.Normal",

+                    "xyz.openbmc_project.State.Critical"

+                    "xyz.openbmc_project.State.Fatal"

+                ]

+            }

+        }

+    ]

+}

diff --git a/test/libpldmresponder_pdr_effecter_test.cpp b/test/libpldmresponder_pdr_effecter_test.cpp
index 72ca0c6..1bf2730 100644
--- a/test/libpldmresponder_pdr_effecter_test.cpp
+++ b/test/libpldmresponder_pdr_effecter_test.cpp
@@ -15,7 +15,8 @@
     auto inPDRRepo = pldm_pdr_init();
     auto outPDRRepo = pldm_pdr_init();
     Repo outRepo(outPDRRepo);
-    Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "./event_jsons/good",
+                    inPDRRepo, nullptr);
     Repo inRepo(inPDRRepo);
     getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR);
 
@@ -108,7 +109,7 @@
     auto inPDRRepo = pldm_pdr_init();
     auto outPDRRepo = pldm_pdr_init();
     Repo outRepo(outPDRRepo);
-    Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "", inPDRRepo, nullptr);
     Repo inRepo(inPDRRepo);
     getRepoByType(inRepo, outRepo, PLDM_NUMERIC_EFFECTER_PDR);
 
@@ -147,7 +148,8 @@
 {
     auto pdrRepo = pldm_pdr_init();
 
-    ASSERT_THROW(Handler("./pdr_jsons/not_there", pdrRepo, nullptr),
+    ASSERT_THROW(Handler("./pdr_jsons/not_there", "./event_jsons/not_there",
+                         pdrRepo, nullptr),
                  std::exception);
 
     pldm_pdr_destroy(pdrRepo);
@@ -158,7 +160,8 @@
     auto inPDRRepo = pldm_pdr_init();
     auto outPDRRepo = pldm_pdr_init();
     Repo outRepo(outPDRRepo);
-    Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "./event_jsons/good",
+                    inPDRRepo, nullptr);
     Repo inRepo(inPDRRepo);
     getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR);
 
diff --git a/test/libpldmresponder_platform_test.cpp b/test/libpldmresponder_platform_test.cpp
index 9af13d5..f487d3b 100644
--- a/test/libpldmresponder_platform_test.cpp
+++ b/test/libpldmresponder_platform_test.cpp
@@ -1,3 +1,4 @@
+#include "libpldmresponder/event_parser.hpp"
 #include "libpldmresponder/pdr.hpp"
 #include "libpldmresponder/pdr_utils.hpp"
 #include "libpldmresponder/platform.hpp"
@@ -26,7 +27,8 @@
     request->request_count = 100;
 
     auto pdrRepo = pldm_pdr_init();
-    Handler handler("./pdr_jsons/state_effecter/good", pdrRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "./event_jsons/good",
+                    pdrRepo, nullptr);
     Repo repo(pdrRepo);
     ASSERT_EQ(repo.empty(), false);
     auto response = handler.getPDR(req, requestPayloadLength);
@@ -57,7 +59,8 @@
     request->request_count = 1;
 
     auto pdrRepo = pldm_pdr_init();
-    Handler handler("./pdr_jsons/state_effecter/good", pdrRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "./event_jsons/good",
+                    pdrRepo, nullptr);
     Repo repo(pdrRepo);
     ASSERT_EQ(repo.empty(), false);
     auto response = handler.getPDR(req, requestPayloadLength);
@@ -82,7 +85,8 @@
     request->request_count = 1;
 
     auto pdrRepo = pldm_pdr_init();
-    Handler handler("./pdr_jsons/state_effecter/good", pdrRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "./event_jsons/good",
+                    pdrRepo, nullptr);
     Repo repo(pdrRepo);
     ASSERT_EQ(repo.empty(), false);
     auto response = handler.getPDR(req, requestPayloadLength);
@@ -105,7 +109,8 @@
     request->record_handle = 1;
 
     auto pdrRepo = pldm_pdr_init();
-    Handler handler("./pdr_jsons/state_effecter/good", pdrRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "./event_jsons/good",
+                    pdrRepo, nullptr);
     Repo repo(pdrRepo);
     ASSERT_EQ(repo.empty(), false);
     auto response = handler.getPDR(req, requestPayloadLength);
@@ -130,7 +135,8 @@
     request->request_count = 100;
 
     auto pdrRepo = pldm_pdr_init();
-    Handler handler("./pdr_jsons/state_effecter/good", pdrRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "./event_jsons/good",
+                    pdrRepo, nullptr);
     Repo repo(pdrRepo);
     ASSERT_EQ(repo.empty(), false);
     auto response = handler.getPDR(req, requestPayloadLength);
@@ -181,7 +187,8 @@
     auto inPDRRepo = pldm_pdr_init();
     auto outPDRRepo = pldm_pdr_init();
     Repo outRepo(outPDRRepo);
-    Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "./event_jsons/good",
+                    inPDRRepo, nullptr);
     Repo inRepo(inPDRRepo);
     getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR);
     pdr_utils::PdrEntry e;
@@ -216,7 +223,8 @@
     auto inPDRRepo = pldm_pdr_init();
     auto outPDRRepo = pldm_pdr_init();
     Repo outRepo(outPDRRepo);
-    Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "./event_jsons/good",
+                    inPDRRepo, nullptr);
     Repo inRepo(inPDRRepo);
     getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR);
     pdr_utils::PdrEntry e;
@@ -255,7 +263,7 @@
     auto inPDRRepo = pldm_pdr_init();
     auto numericEffecterPdrRepo = pldm_pdr_init();
     Repo numericEffecterPDRs(numericEffecterPdrRepo);
-    Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "", inPDRRepo, nullptr);
     Repo inRepo(inPDRRepo);
     getRepoByType(inRepo, numericEffecterPDRs, PLDM_NUMERIC_EFFECTER_PDR);
 
@@ -292,7 +300,7 @@
     auto inPDRRepo = pldm_pdr_init();
     auto numericEffecterPdrRepo = pldm_pdr_init();
     Repo numericEffecterPDRs(numericEffecterPdrRepo);
-    Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "", inPDRRepo, nullptr);
     Repo inRepo(inPDRRepo);
     getRepoByType(inRepo, numericEffecterPDRs, PLDM_NUMERIC_EFFECTER_PDR);
 
@@ -384,3 +392,82 @@
     ASSERT_EQ(le16toh(entityInstance3), 2u);
     ASSERT_EQ(states3, statesCmp3);
 }
+
+TEST(StateSensorHandler, allScenarios)
+{
+    using namespace pldm::responder::events;
+
+    ASSERT_THROW(StateSensorHandler("./event_jsons/malformed1"),
+                 std::exception);
+    ASSERT_THROW(StateSensorHandler("./event_jsons/malformed2"),
+                 std::exception);
+
+    StateSensorHandler handler{"./event_jsons/good"};
+    constexpr uint8_t eventState0 = 0;
+    constexpr uint8_t eventState1 = 1;
+    constexpr uint8_t eventState2 = 2;
+    constexpr uint8_t eventState3 = 3;
+
+    // Event Entry 1
+    {
+        StateSensorEntry entry{1, 64, 1, 0};
+        const auto& [dbusMapping, eventStateMap] = handler.getEventInfo(entry);
+        DBusMapping mapping{"/xyz/abc/def",
+                            "xyz.openbmc_project.example1.value", "value1",
+                            "string"};
+        ASSERT_EQ(mapping == dbusMapping, true);
+
+        const auto& propValue0 = eventStateMap.at(eventState0);
+        const auto& propValue1 = eventStateMap.at(eventState1);
+        const auto& propValue2 = eventStateMap.at(eventState2);
+        PropertyValue value0{std::in_place_type<std::string>,
+                             "xyz.openbmc_project.State.Normal"};
+        PropertyValue value1{std::in_place_type<std::string>,
+                             "xyz.openbmc_project.State.Critical"};
+        PropertyValue value2{std::in_place_type<std::string>,
+                             "xyz.openbmc_project.State.Fatal"};
+        ASSERT_EQ(value0 == propValue0, true);
+        ASSERT_EQ(value1 == propValue1, true);
+        ASSERT_EQ(value2 == propValue2, true);
+    }
+
+    // Event Entry 2
+    {
+        StateSensorEntry entry{1, 64, 1, 1};
+        const auto& [dbusMapping, eventStateMap] = handler.getEventInfo(entry);
+        DBusMapping mapping{"/xyz/abc/def",
+                            "xyz.openbmc_project.example2.value", "value2",
+                            "uint8_t"};
+        ASSERT_EQ(mapping == dbusMapping, true);
+
+        const auto& propValue0 = eventStateMap.at(eventState2);
+        const auto& propValue1 = eventStateMap.at(eventState3);
+        PropertyValue value0{std::in_place_type<uint8_t>, 9};
+        PropertyValue value1{std::in_place_type<uint8_t>, 10};
+        ASSERT_EQ(value0 == propValue0, true);
+        ASSERT_EQ(value1 == propValue1, true);
+    }
+
+    // Event Entry 3
+    {
+        StateSensorEntry entry{2, 67, 2, 0};
+        const auto& [dbusMapping, eventStateMap] = handler.getEventInfo(entry);
+        DBusMapping mapping{"/xyz/abc/ghi",
+                            "xyz.openbmc_project.example3.value", "value3",
+                            "bool"};
+        ASSERT_EQ(mapping == dbusMapping, true);
+
+        const auto& propValue0 = eventStateMap.at(eventState0);
+        const auto& propValue1 = eventStateMap.at(eventState1);
+        PropertyValue value0{std::in_place_type<bool>, false};
+        PropertyValue value1{std::in_place_type<bool>, true};
+        ASSERT_EQ(value0 == propValue0, true);
+        ASSERT_EQ(value1 == propValue1, true);
+    }
+
+    // Invalid Entry
+    {
+        StateSensorEntry entry{0, 0, 0, 0};
+        ASSERT_THROW(handler.getEventInfo(entry), std::out_of_range);
+    }
+}
diff --git a/types.hpp b/types.hpp
index e194c94..d701cfc 100644
--- a/types.hpp
+++ b/types.hpp
@@ -34,6 +34,8 @@
 using EntityInstance = uint16_t;

 using ContainerID = uint16_t;

 using CompositeCount = uint8_t;

+using SensorOffset = uint8_t;

+using EventState = uint8_t;

 

 //!< Subset of the State Set that is supported by a effecter/sensor

 using PossibleStates = std::set<uint8_t>;

diff --git a/utils.cpp b/utils.cpp
index 98e8d21..6a93d99 100644
--- a/utils.cpp
+++ b/utils.cpp
@@ -229,5 +229,57 @@
     return value;
 }
 
+PropertyValue jsonEntryToDbusVal(std::string_view type,
+                                 const nlohmann::json& value)
+{
+    PropertyValue propValue{};
+    if (type == "uint8_t")
+    {
+        propValue = static_cast<uint8_t>(value);
+    }
+    else if (type == "uint16_t")
+    {
+        propValue = static_cast<uint16_t>(value);
+    }
+    else if (type == "uint32_t")
+    {
+        propValue = static_cast<uint32_t>(value);
+    }
+    else if (type == "uint64_t")
+    {
+        propValue = static_cast<uint64_t>(value);
+    }
+    else if (type == "int16_t")
+    {
+        propValue = static_cast<int16_t>(value);
+    }
+    else if (type == "int32_t")
+    {
+        propValue = static_cast<int32_t>(value);
+    }
+    else if (type == "int64_t")
+    {
+        propValue = static_cast<int64_t>(value);
+    }
+    else if (type == "bool")
+    {
+        propValue = static_cast<bool>(value);
+    }
+    else if (type == "double")
+    {
+        propValue = static_cast<double>(value);
+    }
+    else if (type == "string")
+    {
+        propValue = static_cast<std::string>(value);
+    }
+    else
+    {
+        std::cerr << "Unknown D-Bus property type, TYPE=" << type << "\n";
+    }
+
+    return propValue;
+}
+
 } // namespace utils
 } // namespace pldm
diff --git a/utils.hpp b/utils.hpp
index 6ac282d..abf525b 100644
--- a/utils.hpp
+++ b/utils.hpp
@@ -7,6 +7,7 @@
 #include <exception>
 #include <filesystem>
 #include <iostream>
+#include <nlohmann/json.hpp>
 #include <sdbusplus/server.hpp>
 #include <string>
 #include <variant>
@@ -248,6 +249,15 @@
  *  @return uint8_t - MCTP EID
  */
 uint8_t readHostEID();
+/** @brief Convert a value in the JSON to a D-Bus property value
+ *
+ *  @param[in] type - type of the D-Bus property
+ *  @param[in] value - value in the JSON file
+ *
+ *  @return PropertyValue - the D-Bus property value
+ */
+PropertyValue jsonEntryToDbusVal(std::string_view type,
+                                 const nlohmann::json& value);
 
 } // namespace utils
 } // namespace pldm