Enabled Electrical Energy Measurement in example-energy-management-ap… (#31622)

* Enabled Electrical Energy Measurement in example-energy-management-app ZAP and regen all.

* Added ElectricalEnergyMeasurement to chip-repl __init__.py

* Restyled by isort

* Changed feature map to indicate CUME and IMP support only

* Adding into __all__ some missing clusters which are causing flake8 issues.

* Removed out of date comment

* Added a test event trigger to fake energy reporting readings into the EEM cluster (hooks ready for EPM cluster)

* Added new Energy Reporting TE Trigger delegate

* Updated random calculation and scaled into mWh (divide by 3600)

* Restyled by whitespace

* Restyled by gn

* Removed accidental launch.json inclusion

* Fix for ARM linux etc builds due to gn dependency check error

* Added code review suggestions.

* More code review suggestions fixed.

* Added electrical-energy-measurement-server to CMakelist to fix linker issue.

---------

Co-authored-by: Restyled.io <commits@restyled.io>
diff --git a/examples/energy-management-app/energy-management-common/energy-management-app.matter b/examples/energy-management-app/energy-management-common/energy-management-app.matter
index 2c580b5..dae1893 100644
--- a/examples/energy-management-app/energy-management-common/energy-management-app.matter
+++ b/examples/energy-management-app/energy-management-common/energy-management-app.matter
@@ -900,6 +900,85 @@
   fabric command access(invoke: administer) KeySetReadAllIndices(): KeySetReadAllIndicesResponse = 4;
 }
 
+/** This cluster provides a mechanism for querying data about the electrical energy imported or provided by the server. */
+provisional cluster ElectricalEnergyMeasurement = 145 {
+  revision 1;
+
+  enum MeasurementTypeEnum : enum16 {
+    kUnspecified = 0;
+    kVoltage = 1;
+    kActiveCurrent = 2;
+    kReactiveCurrent = 3;
+    kApparentCurrent = 4;
+    kActivePower = 5;
+    kReactivePower = 6;
+    kApparentPower = 7;
+    kRMSVoltage = 8;
+    kRMSCurrent = 9;
+    kRMSPower = 10;
+    kFrequency = 11;
+    kPowerFactor = 12;
+    kNeutralCurrent = 13;
+    kElectricalEnergy = 14;
+  }
+
+  bitmap Feature : bitmap32 {
+    kImportedEnergy = 0x1;
+    kExportedEnergy = 0x2;
+    kCumulativeEnergy = 0x4;
+    kPeriodicEnergy = 0x8;
+  }
+
+  struct MeasurementAccuracyRangeStruct {
+    int64s rangeMin = 0;
+    int64s rangeMax = 1;
+    optional percent100ths percentMax = 2;
+    optional percent100ths percentMin = 3;
+    optional percent100ths percentTypical = 4;
+    optional int64u fixedMax = 5;
+    optional int64u fixedMin = 6;
+    optional int64u fixedTypical = 7;
+  }
+
+  struct MeasurementAccuracyStruct {
+    MeasurementTypeEnum measurementType = 0;
+    boolean measured = 1;
+    int64s minMeasuredValue = 2;
+    int64s maxMeasuredValue = 3;
+    MeasurementAccuracyRangeStruct accuracyRanges[] = 4;
+  }
+
+  struct EnergyMeasurementStruct {
+    int64s energy = 0;
+    optional epoch_s startTimestamp = 1;
+    optional epoch_s endTimestamp = 2;
+    optional systime_ms startSystime = 3;
+    optional systime_ms endSystime = 4;
+  }
+
+  info event CumulativeEnergyMeasured = 0 {
+    optional EnergyMeasurementStruct energyImported = 0;
+    optional EnergyMeasurementStruct energyExported = 1;
+  }
+
+  info event PeriodicEnergyMeasured = 1 {
+    optional EnergyMeasurementStruct energyImported = 0;
+    optional EnergyMeasurementStruct energyExported = 1;
+  }
+
+  readonly attribute MeasurementAccuracyStruct accuracy = 0;
+  readonly attribute optional nullable EnergyMeasurementStruct cumulativeEnergyImported = 1;
+  readonly attribute optional nullable EnergyMeasurementStruct cumulativeEnergyExported = 2;
+  readonly attribute optional nullable EnergyMeasurementStruct periodicEnergyImported = 3;
+  readonly attribute optional nullable EnergyMeasurementStruct periodicEnergyExported = 4;
+  readonly attribute command_id generatedCommandList[] = 65528;
+  readonly attribute command_id acceptedCommandList[] = 65529;
+  readonly attribute event_id eventList[] = 65530;
+  readonly attribute attrib_id attributeList[] = 65531;
+  readonly attribute bitmap32 featureMap = 65532;
+  readonly attribute int16u clusterRevision = 65533;
+}
+
 /** This cluster allows a client to manage the power draw of a device. An example of such a client could be an Energy Management System (EMS) which controls an Energy Smart Appliance (ESA). */
 provisional cluster DeviceEnergyManagement = 152 {
   revision 3;
@@ -1598,6 +1677,18 @@
     callback attribute clusterRevision;
   }
 
+  server cluster ElectricalEnergyMeasurement {
+    emits event CumulativeEnergyMeasured;
+    callback attribute accuracy;
+    callback attribute cumulativeEnergyImported;
+    callback attribute generatedCommandList;
+    callback attribute acceptedCommandList;
+    callback attribute eventList;
+    callback attribute attributeList;
+    ram      attribute featureMap default = 5;
+    ram      attribute clusterRevision default = 1;
+  }
+
   server cluster DeviceEnergyManagement {
     emits event PowerAdjustStart;
     emits event PowerAdjustEnd;
diff --git a/examples/energy-management-app/energy-management-common/energy-management-app.zap b/examples/energy-management-app/energy-management-common/energy-management-app.zap
index 78485df..0e1f15b 100644
--- a/examples/energy-management-app/energy-management-common/energy-management-app.zap
+++ b/examples/energy-management-app/energy-management-common/energy-management-app.zap
@@ -2518,6 +2518,154 @@
           ]
         },
         {
+          "name": "Electrical Energy Measurement",
+          "code": 145,
+          "mfgCode": null,
+          "define": "ELECTRICAL_ENERGY_MEASUREMENT_CLUSTER",
+          "side": "server",
+          "enabled": 1,
+          "apiMaturity": "provisional",
+          "attributes": [
+            {
+              "name": "Accuracy",
+              "code": 0,
+              "mfgCode": null,
+              "side": "server",
+              "type": "MeasurementAccuracyStruct",
+              "included": 1,
+              "storageOption": "External",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": null,
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "CumulativeEnergyImported",
+              "code": 1,
+              "mfgCode": null,
+              "side": "server",
+              "type": "EnergyMeasurementStruct",
+              "included": 1,
+              "storageOption": "External",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": null,
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "GeneratedCommandList",
+              "code": 65528,
+              "mfgCode": null,
+              "side": "server",
+              "type": "array",
+              "included": 1,
+              "storageOption": "External",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": null,
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "AcceptedCommandList",
+              "code": 65529,
+              "mfgCode": null,
+              "side": "server",
+              "type": "array",
+              "included": 1,
+              "storageOption": "External",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": null,
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "EventList",
+              "code": 65530,
+              "mfgCode": null,
+              "side": "server",
+              "type": "array",
+              "included": 1,
+              "storageOption": "External",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": null,
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "AttributeList",
+              "code": 65531,
+              "mfgCode": null,
+              "side": "server",
+              "type": "array",
+              "included": 1,
+              "storageOption": "External",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": null,
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "FeatureMap",
+              "code": 65532,
+              "mfgCode": null,
+              "side": "server",
+              "type": "bitmap32",
+              "included": 1,
+              "storageOption": "RAM",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "5",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "ClusterRevision",
+              "code": 65533,
+              "mfgCode": null,
+              "side": "server",
+              "type": "int16u",
+              "included": 1,
+              "storageOption": "RAM",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "1",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            }
+          ],
+          "events": [
+            {
+              "name": "CumulativeEnergyMeasured",
+              "code": 0,
+              "mfgCode": null,
+              "side": "server",
+              "included": 1
+            }
+          ]
+        },
+        {
           "name": "Device Energy Management",
           "code": 152,
           "mfgCode": null,
diff --git a/examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h b/examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h
index df757f7..f1c3eac 100644
--- a/examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h
+++ b/examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h
@@ -60,6 +60,56 @@
      */
     static void ApplicationCallbackHandler(const EVSECbInfo * cb, intptr_t arg);
 
+    /**
+     * @brief   Allows a client application to send in power readings into the system
+     *
+     * @param[in]  aEndpointId     - Endpoint to send to EPM Cluster
+     * @param[in]  aActivePower_mW - Power measured in milli-watts
+     * @param[in]  aVoltage_mV     - Voltage measured in milli-volts
+     * @param[in]  aCurrent_mA     - Current measured in milli-amps
+     */
+    CHIP_ERROR SendPowerReading(EndpointId aEndpointId, int64_t aActivePower_mW, int64_t aVoltage_mV, int64_t aCurrent_mA);
+
+    /**
+     * @brief   Allows a client application to send in energy readings into the system
+     *
+     *          This is a helper function to add timestamps to the readings
+     *
+     * @param[in]  aCumulativeEnergyImported -total energy imported in milli-watthours
+     * @param[in]  aCumulativeEnergyExported -total energy exported in milli-watthours
+     */
+    CHIP_ERROR SendEnergyReading(EndpointId aEndpointId, int64_t aCumulativeEnergyImported, int64_t aCumulativeEnergyExported);
+
+    /**  Fake Meter data generation - used for testing EPM/EEM clusters */
+    /**
+     * @brief   Starts a fake load/generator to periodically callback the power and energy
+     *          clusters.
+     * @param[in]   aEndpointId  - which endpoint is the meter to be updated on
+     * @param[in]   aPower_mW    - the mean power of the load
+     *                             Positive power indicates Imported energy (e.g. a load)
+     *                             Negative power indicated Exported energy (e.g. a generator)
+     * @param[in]   aPowerRandomness_mW  This is used to scale random power fluctuations around the mean power of the load
+     *
+     * @param[in]   aInterval_s  - the callback interval in seconds
+     * @param[in]   bReset       - boolean: true will reset the energy values to 0
+     */
+    void StartFakeReadings(EndpointId aEndpointId, int64_t aPower_mW, uint32_t aPowerRandomness_mW, uint8_t aInterval_s,
+                           bool bReset);
+
+    /**
+     * @brief   Stops any active updates to the fake load data callbacks
+     */
+    void StopFakeReadings();
+
+    /**
+     * @brief   Sends fake meter data into the cluster and restarts the timer
+     */
+    void FakeReadingsUpdate();
+    /**
+     * @brief   Timer expiry callback to handle fake load
+     */
+    static void FakeReadingsTimerExpiry(System::Layer * systemLayer, void * manufacturer);
+
 private:
     EnergyEvseManager * mInstance;
 
diff --git a/examples/energy-management-app/energy-management-common/include/EnergyEvseDelegateImpl.h b/examples/energy-management-app/energy-management-common/include/EnergyEvseDelegateImpl.h
index 558f7c1..e6f5c8c 100644
--- a/examples/energy-management-app/energy-management-common/include/EnergyEvseDelegateImpl.h
+++ b/examples/energy-management-app/energy-management-common/include/EnergyEvseDelegateImpl.h
@@ -26,6 +26,14 @@
 #include <cstring>
 
 using chip::Protocols::InteractionModel::Status;
+
+/**
+ * @brief   Helper function to get current timestamp in Epoch format
+ *
+ * @param   chipEpoch reference to hold return timestamp
+ */
+CHIP_ERROR GetEpochTS(uint32_t & chipEpoch);
+
 namespace chip {
 namespace app {
 namespace Clusters {
diff --git a/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp b/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp
index fe51c9d..70cd63e 100644
--- a/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp
+++ b/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp
@@ -18,12 +18,16 @@
 
 #include <EVSEManufacturerImpl.h>
 #include <EnergyEvseManager.h>
+#include <app/clusters/electrical-energy-measurement-server/EnergyReportingTestEventTriggerDelegate.h>
+#include <app/clusters/electrical-energy-measurement-server/electrical-energy-measurement-server.h>
 #include <app/clusters/energy-evse-server/EnergyEvseTestEventTriggerDelegate.h>
 
 using namespace chip;
 using namespace chip::app;
 using namespace chip::app::Clusters;
 using namespace chip::app::Clusters::EnergyEvse;
+using namespace chip::app::Clusters::ElectricalEnergyMeasurement;
+using namespace chip::app::Clusters::ElectricalEnergyMeasurement::Structs;
 
 CHIP_ERROR EVSEManufacturer::Init()
 {
@@ -90,6 +94,179 @@
 }
 
 /**
+ * @brief   Allows a client application to send in power readings into the system
+ *
+ * @param[in]  aEndpointId     - Endpoint to send to EPM Cluster
+ * @param[in]  aActivePower_mW - Power measured in milli-watts
+ * @param[in]  aVoltage_mV     - Voltage measured in milli-volts
+ * @param[in]  aCurrent_mA     - Current measured in milli-amps
+ */
+CHIP_ERROR EVSEManufacturer::SendPowerReading(EndpointId aEndpointId, int64_t aActivePower_mW, int64_t aVoltage_mV,
+                                              int64_t aCurrent_mA)
+{
+    // TODO add Power Readings when EPM cluster is merged
+
+    return CHIP_NO_ERROR;
+}
+
+/**
+ * @brief   Allows a client application to send in energy readings into the system
+ *
+ *          This is a helper function to add timestamps to the readings
+ *
+ * @param[in]  aCumulativeEnergyImported -total energy imported in milli-watthours
+ * @param[in]  aCumulativeEnergyExported -total energy exported in milli-watthours
+ */
+CHIP_ERROR EVSEManufacturer::SendEnergyReading(EndpointId aEndpointId, int64_t aCumulativeEnergyImported,
+                                               int64_t aCumulativeEnergyExported)
+{
+    MeasurementData * data = MeasurementDataForEndpoint(aEndpointId);
+
+    EnergyMeasurementStruct::Type energyImported;
+    EnergyMeasurementStruct::Type energyExported;
+
+    // Get current timestamp
+    uint32_t currentTimestamp;
+    CHIP_ERROR err = GetEpochTS(currentTimestamp);
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(AppServer, "GetEpochTS returned error getting timestamp");
+        return err;
+    }
+
+    /** IMPORT */
+    // Copy last endTimestamp into new startTimestamp if it exists
+    energyImported.startTimestamp.ClearValue();
+    if (data->cumulativeImported.HasValue())
+    {
+        energyImported.startTimestamp = data->cumulativeImported.Value().endTimestamp;
+    }
+
+    energyImported.endTimestamp.SetValue(currentTimestamp);
+    energyImported.energy = aCumulativeEnergyImported;
+
+    /** EXPORT */
+    // Copy last endTimestamp into new startTimestamp if it exists
+    energyExported.startTimestamp.ClearValue();
+    if (data->cumulativeExported.HasValue())
+    {
+        energyExported.startTimestamp = data->cumulativeExported.Value().endTimestamp;
+    }
+    energyExported.endTimestamp.SetValue(currentTimestamp);
+    energyExported.energy = aCumulativeEnergyExported;
+
+    // call the SDK to update attributes and generate an event
+    if (!NotifyCumulativeEnergyMeasured(aEndpointId, MakeOptional(energyImported), MakeOptional(energyExported)))
+    {
+        ChipLogError(AppServer, "Failed to notify Cumulative Energy reading.");
+        return CHIP_ERROR_INTERNAL;
+    }
+
+    return CHIP_NO_ERROR;
+}
+
+struct FakeReadingsData
+{
+    bool bEnabled;                /* If enabled then the timer callback will re-trigger */
+    EndpointId mEndpointId;       /* Which endpoint the meter is on */
+    uint8_t mInterval_s;          /* Interval in seconds to callback */
+    int64_t mPower_mW;            /* Power on the load in mW (signed value) +ve = imported */
+    uint32_t mPowerRandomness_mW; /* The amount to randomize the Power on the load in mW */
+    /* These energy values can only be positive values.
+     * however the underlying energy type (power_mWh) is signed, so keeping with that convention */
+    int64_t mTotalEnergyImported = 0; /* Energy Imported which is updated if mPower > 0 */
+    int64_t mTotalEnergyExported = 0; /* Energy Imported which is updated if mPower < 0 */
+};
+
+static FakeReadingsData gFakeReadingsData;
+
+/* This helper routine starts and handles a callback */
+/**
+ * @brief   Starts a fake load/generator to periodically callback the power and energy
+ *          clusters.
+ * @param[in]   aEndpointId  - which endpoint is the meter to be updated on
+ * @param[in]   aPower_mW    - the mean power of the load
+ *                             Positive power indicates Imported energy (e.g. a load)
+ *                             Negative power indicated Exported energy (e.g. a generator)
+ * @param[in]   aPowerRandomness_mW  This is used to define the std.dev of the
+ *                             random power values around the mean power of the load
+ *
+ * @param[in]   aInterval_s  - the callback interval in seconds
+ * @param[in]   bReset       - boolean: true will reset the energy values to 0
+ */
+void EVSEManufacturer::StartFakeReadings(EndpointId aEndpointId, int64_t aPower_mW, uint32_t aPowerRandomness_mW,
+                                         uint8_t aInterval_s, bool bReset)
+{
+    gFakeReadingsData.bEnabled            = true;
+    gFakeReadingsData.mEndpointId         = aEndpointId;
+    gFakeReadingsData.mPower_mW           = aPower_mW;
+    gFakeReadingsData.mPowerRandomness_mW = aPowerRandomness_mW;
+    gFakeReadingsData.mInterval_s         = aInterval_s;
+
+    if (bReset)
+    {
+        gFakeReadingsData.mTotalEnergyImported = 0;
+        gFakeReadingsData.mTotalEnergyExported = 0;
+    }
+
+    // Call update function to kick off regular readings
+    FakeReadingsUpdate();
+}
+/**
+ * @brief   Stops any active updates to the fake load data callbacks
+ */
+void EVSEManufacturer::StopFakeReadings()
+{
+    gFakeReadingsData.bEnabled = false;
+}
+/**
+ * @brief   Sends fake meter data into the cluster and restarts the timer
+ */
+void EVSEManufacturer::FakeReadingsUpdate()
+{
+    /* Check to see if the fake Load is still running - don't send updates if the timer was already cancelled */
+    if (!gFakeReadingsData.bEnabled)
+    {
+        return;
+    }
+
+    // Update meter values
+    // Avoid using floats - so we will do a basic rand() call which will generate a integer value between 0 and RAND_MAX
+    // first compute power as a mean + some random value in range 0 to mPowerRandomness_mW
+    int64_t power = (rand() % gFakeReadingsData.mPowerRandomness_mW);
+    power += gFakeReadingsData.mPower_mW; // add in the base power
+
+    // TODO call the EPM cluster to send a power reading
+
+    // update the energy meter - we'll assume that the power has been constant during the previous interval
+    if (gFakeReadingsData.mPower_mW > 0)
+    {
+        // Positive power - means power is imported
+        gFakeReadingsData.mTotalEnergyImported += ((power * gFakeReadingsData.mInterval_s) / 3600);
+    }
+    else
+    {
+        // Negative power - means power is exported, but the cumulative energy is positive
+        gFakeReadingsData.mTotalEnergyExported += ((-power * gFakeReadingsData.mInterval_s) / 3600);
+    }
+
+    SendEnergyReading(gFakeReadingsData.mEndpointId, gFakeReadingsData.mTotalEnergyImported,
+                      gFakeReadingsData.mTotalEnergyExported);
+
+    // start/restart the timer
+    DeviceLayer::SystemLayer().StartTimer(System::Clock::Seconds32(gFakeReadingsData.mInterval_s), FakeReadingsTimerExpiry, this);
+}
+/**
+ * @brief   Timer expiry callback to handle fake load
+ */
+void EVSEManufacturer::FakeReadingsTimerExpiry(System::Layer * systemLayer, void * manufacturer)
+{
+    EVSEManufacturer * mn = reinterpret_cast<EVSEManufacturer *>(manufacturer);
+
+    mn->FakeReadingsUpdate();
+}
+
+/**
  * @brief    Main Callback handler - to be implemented by Manufacturer
  *
  * @param    EVSECbInfo describes the type of call back, and a union of structs
@@ -231,6 +408,37 @@
     dg->HwDiagnosticsComplete();
 }
 
+void SetTestEventTrigger_FakeReadingsLoadStart()
+{
+    EVSEManufacturer * mn = GetEvseManufacturer();
+    VerifyOrDieWithMsg(mn != nullptr, AppServer, "EVSEManufacturer is null");
+
+    int64_t aPower_mW            = 1'000'000; // Fake load 1000 W
+    uint32_t aPowerRandomness_mW = 20'000;    // randomness 20W
+    uint8_t aInterval_s          = 2;         // 2s updates
+    bool bReset                  = true;
+    mn->StartFakeReadings(EndpointId(1), aPower_mW, aPowerRandomness_mW, aInterval_s, bReset);
+}
+
+void SetTestEventTrigger_FakeReadingsGeneratorStart()
+{
+    EVSEManufacturer * mn = GetEvseManufacturer();
+    VerifyOrDieWithMsg(mn != nullptr, AppServer, "EVSEManufacturer is null");
+
+    int64_t aPower_mW            = -3'000'000; // Fake Generator -3000 W
+    uint32_t aPowerRandomness_mW = 20'000;     // randomness 20W
+    uint8_t aInterval_s          = 5;          // 5s updates
+    bool bReset                  = true;
+    mn->StartFakeReadings(EndpointId(1), aPower_mW, aPowerRandomness_mW, aInterval_s, bReset);
+}
+
+void SetTestEventTrigger_FakeReadingsStop()
+{
+    EVSEManufacturer * mn = GetEvseManufacturer();
+    VerifyOrDieWithMsg(mn != nullptr, AppServer, "EVSEManufacturer is null");
+    mn->StopFakeReadings();
+}
+
 bool HandleEnergyEvseTestEventTrigger(uint64_t eventTrigger)
 {
     EnergyEvseTrigger trigger = static_cast<EnergyEvseTrigger>(eventTrigger);
@@ -284,3 +492,29 @@
 
     return true;
 }
+
+bool HandleEnergyReportingTestEventTrigger(uint64_t eventTrigger)
+{
+    EnergyReportingTrigger trigger = static_cast<EnergyReportingTrigger>(eventTrigger);
+
+    switch (trigger)
+    {
+    case EnergyReportingTrigger::kFakeReadingsStop:
+        ChipLogProgress(Support, "[EnergyReporting-Test-Event] => Stop Fake load");
+        SetTestEventTrigger_FakeReadingsStop();
+        break;
+    case EnergyReportingTrigger::kFakeReadingsLoadStart_1kW_2s:
+        ChipLogProgress(Support, "[EnergyReporting-Test-Event] => Start Fake load 1kW @2s Import");
+        SetTestEventTrigger_FakeReadingsLoadStart();
+        break;
+    case EnergyReportingTrigger::kFakeReadingsGenStart_3kW_5s:
+        ChipLogProgress(Support, "[EnergyReporting-Test-Event] => Start Fake generator 3kW @5s Export");
+        SetTestEventTrigger_FakeReadingsGeneratorStart();
+        break;
+
+    default:
+        return false;
+    }
+
+    return true;
+}
diff --git a/examples/energy-management-app/esp32/main/CMakeLists.txt b/examples/energy-management-app/esp32/main/CMakeLists.txt
index 46f97d7..edba8f9 100644
--- a/examples/energy-management-app/esp32/main/CMakeLists.txt
+++ b/examples/energy-management-app/esp32/main/CMakeLists.txt
@@ -65,6 +65,7 @@
                       "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/groups-server"
                       "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/group-key-mgmt-server"
                       "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/mode-base-server"
+                      "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/electrical-energy-measurement-server"
 )
 
 set(PRIV_REQUIRES_LIST chip QRCode bt led_strip app_update openthread driver nvs_flash spi_flash)
diff --git a/examples/energy-management-app/linux/args.gni b/examples/energy-management-app/linux/args.gni
index b7c71c3..e1000e6 100644
--- a/examples/energy-management-app/linux/args.gni
+++ b/examples/energy-management-app/linux/args.gni
@@ -30,3 +30,4 @@
 
 chip_enable_read_client = false
 chip_enable_energy_evse_trigger = true
+chip_enable_energy_reporting_trigger = true
diff --git a/examples/energy-management-app/linux/main.cpp b/examples/energy-management-app/linux/main.cpp
index 824fa17..a150b82 100644
--- a/examples/energy-management-app/linux/main.cpp
+++ b/examples/energy-management-app/linux/main.cpp
@@ -208,7 +208,6 @@
     }
 
     /* Now create EVSEManufacturer */
-    // TODO  this takes just the EVSE Instance for now, but will need the DEM adding
     gEvseManufacturer = std::make_unique<EVSEManufacturer>(gEvseInstance.get());
     if (!gEvseManufacturer)
     {
diff --git a/examples/platform/linux/AppMain.cpp b/examples/platform/linux/AppMain.cpp
index 933502d..04274ab 100644
--- a/examples/platform/linux/AppMain.cpp
+++ b/examples/platform/linux/AppMain.cpp
@@ -86,6 +86,9 @@
 #if CHIP_DEVICE_CONFIG_ENABLE_ENERGY_EVSE_TRIGGER
 #include <app/clusters/energy-evse-server/EnergyEvseTestEventTriggerDelegate.h>
 #endif
+#if CHIP_DEVICE_CONFIG_ENABLE_ENERGY_REPORTING_TRIGGER
+#include <app/clusters/electrical-energy-measurement-server/EnergyReportingTestEventTriggerDelegate.h>
+#endif
 #include <app/TestEventTriggerDelegate.h>
 
 #include <signal.h>
@@ -571,6 +574,12 @@
     };
     otherDelegate = &energyEvseTestEventTriggerDelegate;
 #endif
+#if CHIP_DEVICE_CONFIG_ENABLE_ENERGY_REPORTING_TRIGGER
+    static EnergyReportingTestEventTriggerDelegate energyReportingTestEventTriggerDelegate{
+        ByteSpan(LinuxDeviceOptions::GetInstance().testEventTriggerEnableKey), otherDelegate
+    };
+    otherDelegate = &energyReportingTestEventTriggerDelegate;
+#endif
 
     // For general testing of TestEventTrigger, we have a common "core" event trigger delegate.
     static SampleTestEventTriggerDelegate testEventTriggerDelegate;
diff --git a/examples/platform/linux/BUILD.gn b/examples/platform/linux/BUILD.gn
index fbbf7e1..f82702b 100644
--- a/examples/platform/linux/BUILD.gn
+++ b/examples/platform/linux/BUILD.gn
@@ -23,6 +23,7 @@
   chip_enable_smoke_co_trigger = false
   chip_enable_boolean_state_configuration_trigger = false
   chip_enable_energy_evse_trigger = false
+  chip_enable_energy_reporting_trigger = false
 }
 
 config("app-main-config") {
@@ -47,6 +48,10 @@
   sources = [ "${chip_root}/src/app/clusters/energy-evse-server/EnergyEvseTestEventTriggerDelegate.h" ]
 }
 
+source_set("energy-reporting-test-event-trigger") {
+  sources = [ "${chip_root}/src/app/clusters/electrical-energy-measurement-server/EnergyReportingTestEventTriggerDelegate.h" ]
+}
+
 source_set("app-main") {
   defines = [ "ENABLE_TRACING=${matter_enable_tracing_support}" ]
   sources = [
@@ -71,6 +76,7 @@
   public_deps = [
     ":boolean-state-configuration-test-event-trigger",
     ":energy-evse-test-event-trigger",
+    ":energy-reporting-test-event-trigger",
     ":smco-test-event-trigger",
     "${chip_root}/src/lib",
     "${chip_root}/src/platform/logging:force_stdio",
@@ -110,6 +116,7 @@
     "CHIP_DEVICE_CONFIG_ENABLE_SMOKE_CO_TRIGGER=${chip_enable_smoke_co_trigger}",
     "CHIP_DEVICE_CONFIG_ENABLE_BOOLEAN_STATE_CONFIGURATION_TRIGGER=${chip_enable_boolean_state_configuration_trigger}",
     "CHIP_DEVICE_CONFIG_ENABLE_ENERGY_EVSE_TRIGGER=${chip_enable_energy_evse_trigger}",
+    "CHIP_DEVICE_CONFIG_ENABLE_ENERGY_REPORTING_TRIGGER=${chip_enable_energy_reporting_trigger}",
   ]
 
   public_configs = [ ":app-main-config" ]
diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni
index 7f8f477..6404eb3 100644
--- a/src/app/chip_data_model.gni
+++ b/src/app/chip_data_model.gni
@@ -352,6 +352,13 @@
           "${_app_root}/clusters/${cluster}/BDXDiagnosticLogsProvider.h",
           "${_app_root}/clusters/${cluster}/DiagnosticLogsProviderDelegate.h",
         ]
+      } else if (cluster == "electrical-energy-measurement-server") {
+        sources += [
+          "${_app_root}/clusters/${cluster}/${cluster}.cpp",
+          "${_app_root}/clusters/${cluster}/${cluster}.h",
+          "${_app_root}/clusters/${cluster}/EnergyReportingTestEventTriggerDelegate.cpp",
+          "${_app_root}/clusters/${cluster}/EnergyReportingTestEventTriggerDelegate.h",
+        ]
       } else {
         sources += [ "${_app_root}/clusters/${cluster}/${cluster}.cpp" ]
       }
diff --git a/src/app/clusters/electrical-energy-measurement-server/EnergyReportingTestEventTriggerDelegate.cpp b/src/app/clusters/electrical-energy-measurement-server/EnergyReportingTestEventTriggerDelegate.cpp
new file mode 100644
index 0000000..210ab40
--- /dev/null
+++ b/src/app/clusters/electrical-energy-measurement-server/EnergyReportingTestEventTriggerDelegate.cpp
@@ -0,0 +1,40 @@
+/*
+ *
+ *    Copyright (c) 2024 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include "EnergyReportingTestEventTriggerDelegate.h"
+
+namespace chip {
+
+bool EnergyReportingTestEventTriggerDelegate::DoesEnableKeyMatch(const ByteSpan & enableKey) const
+{
+    return !mEnableKey.empty() && mEnableKey.data_equal(enableKey);
+}
+
+CHIP_ERROR EnergyReportingTestEventTriggerDelegate::HandleEventTrigger(uint64_t eventTrigger)
+{
+    if (HandleEnergyReportingTestEventTrigger(eventTrigger))
+    {
+        return CHIP_NO_ERROR;
+    }
+    if (mOtherDelegate != nullptr)
+    {
+        return mOtherDelegate->HandleEventTrigger(eventTrigger);
+    }
+    return CHIP_ERROR_INVALID_ARGUMENT;
+}
+
+} // namespace chip
diff --git a/src/app/clusters/electrical-energy-measurement-server/EnergyReportingTestEventTriggerDelegate.h b/src/app/clusters/electrical-energy-measurement-server/EnergyReportingTestEventTriggerDelegate.h
new file mode 100644
index 0000000..a7beef6
--- /dev/null
+++ b/src/app/clusters/electrical-energy-measurement-server/EnergyReportingTestEventTriggerDelegate.h
@@ -0,0 +1,83 @@
+/*
+ *
+ *    Copyright (c) 2024 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#pragma once
+
+#include <app-common/zap-generated/cluster-objects.h>
+#include <app/TestEventTriggerDelegate.h>
+
+namespace chip {
+
+/*
+ * These Test EventTrigger values can be used to fake meter reading data
+ *
+ * They are sent along with the enableKey (manufacturer defined secret)
+ * in the General Diagnostic cluster TestEventTrigger command
+ */
+enum class EnergyReportingTrigger : uint64_t
+{
+    // We use the Electrical Energy Measurement cluster ID as our TE trigger space
+    // Stop Fake readings
+    kFakeReadingsStop = 0x0091'0000'0000'0000,
+    // Fake a load (importing) readings at 1kW 230V 4.34A with 2s updates
+    kFakeReadingsLoadStart_1kW_2s = 0x0091'0000'0000'0001,
+    // Fake a generator (exporting) readings at 3kW 230V 3.33A with 5s updates
+    kFakeReadingsGenStart_3kW_5s = 0x0091'0000'0000'0002,
+
+};
+
+class EnergyReportingTestEventTriggerDelegate : public TestEventTriggerDelegate
+{
+public:
+    /**
+     * This class expects the enableKey ByteSpan to be valid forever.
+     * Typically this feature is only enabled in certification testing
+     * and uses a static secret key in the device for testing (e.g. in factory data)
+     */
+    explicit EnergyReportingTestEventTriggerDelegate(const ByteSpan & enableKey, TestEventTriggerDelegate * otherDelegate) :
+        mEnableKey(enableKey), mOtherDelegate(otherDelegate)
+    {}
+
+    /* This function returns True if the enableKey received in the TestEventTrigger command
+     * matches the value passed into the constructor.
+     */
+    bool DoesEnableKeyMatch(const ByteSpan & enableKey) const override;
+
+    /** This function must return True if the eventTrigger is recognised and handled
+     *  It must return False to allow a higher level TestEvent handler to check other
+     *  clusters that may handle it.
+     */
+    CHIP_ERROR HandleEventTrigger(uint64_t eventTrigger) override;
+
+private:
+    ByteSpan mEnableKey;
+    TestEventTriggerDelegate * mOtherDelegate;
+};
+
+} // namespace chip
+
+/**
+ * @brief User handler for handling the test event trigger
+ *
+ * @note If TestEventTrigger is enabled, it needs to be implemented in the app
+ *
+ * @param eventTrigger Event trigger to handle
+ *
+ * @retval true on success
+ * @retval false if error happened
+ */
+bool HandleEnergyReportingTestEventTrigger(uint64_t eventTrigger);
diff --git a/src/app/clusters/electrical-energy-measurement-server/electrical-energy-measurement-server.cpp b/src/app/clusters/electrical-energy-measurement-server/electrical-energy-measurement-server.cpp
index fcc75ef..728b41d 100644
--- a/src/app/clusters/electrical-energy-measurement-server/electrical-energy-measurement-server.cpp
+++ b/src/app/clusters/electrical-energy-measurement-server/electrical-energy-measurement-server.cpp
@@ -33,36 +33,9 @@
 using namespace chip::app::Clusters::ElectricalEnergyMeasurement::Attributes;
 using namespace chip::app::Clusters::ElectricalEnergyMeasurement::Structs;
 
-struct MeasurementData
-{
-    MeasurementAccuracyStruct::Type measurementAccuracy;
-    Optional<EnergyMeasurementStruct::Type> cumulativeImported;
-    Optional<EnergyMeasurementStruct::Type> cumulativeExported;
-    Optional<EnergyMeasurementStruct::Type> periodicImported;
-    Optional<EnergyMeasurementStruct::Type> periodicExported;
-};
-
 MeasurementData
     gMeasurements[EMBER_AF_ELECTRICAL_ENERGY_MEASUREMENT_CLUSTER_SERVER_ENDPOINT_COUNT + CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT];
 
-MeasurementData * MeasurementDataForEndpoint(EndpointId endpointId)
-{
-    auto index = emberAfGetClusterServerEndpointIndex(endpointId, app::Clusters::ElectricalEnergyMeasurement::Id,
-                                                      EMBER_AF_ELECTRICAL_ENERGY_MEASUREMENT_CLUSTER_SERVER_ENDPOINT_COUNT);
-
-    if (index == kEmberInvalidEndpointIndex)
-    {
-        return nullptr;
-    }
-
-    if (index >= EMBER_AF_ELECTRICAL_ENERGY_MEASUREMENT_CLUSTER_SERVER_ENDPOINT_COUNT)
-    {
-        ChipLogError(NotSpecified, "Internal error: invalid/unexpected energy measurement index.");
-        return nullptr;
-    }
-    return &gMeasurements[index];
-}
-
 class ElectricalEnergyMeasurementAttrAccess : public app::AttributeAccessInterface
 {
 public:
@@ -126,6 +99,24 @@
 namespace Clusters {
 namespace ElectricalEnergyMeasurement {
 
+MeasurementData * MeasurementDataForEndpoint(EndpointId endpointId)
+{
+    auto index = emberAfGetClusterServerEndpointIndex(endpointId, app::Clusters::ElectricalEnergyMeasurement::Id,
+                                                      EMBER_AF_ELECTRICAL_ENERGY_MEASUREMENT_CLUSTER_SERVER_ENDPOINT_COUNT);
+
+    if (index == kEmberInvalidEndpointIndex)
+    {
+        return nullptr;
+    }
+
+    if (index >= EMBER_AF_ELECTRICAL_ENERGY_MEASUREMENT_CLUSTER_SERVER_ENDPOINT_COUNT)
+    {
+        ChipLogError(NotSpecified, "Internal error: invalid/unexpected energy measurement index.");
+        return nullptr;
+    }
+    return &gMeasurements[index];
+}
+
 CHIP_ERROR SetMeasurementAccuracy(EndpointId endpointId, const MeasurementAccuracyStruct::Type & accuracy)
 {
 
diff --git a/src/app/clusters/electrical-energy-measurement-server/electrical-energy-measurement-server.h b/src/app/clusters/electrical-energy-measurement-server/electrical-energy-measurement-server.h
index 8647b9b..9c3d876 100644
--- a/src/app/clusters/electrical-energy-measurement-server/electrical-energy-measurement-server.h
+++ b/src/app/clusters/electrical-energy-measurement-server/electrical-energy-measurement-server.h
@@ -26,6 +26,15 @@
 namespace Clusters {
 namespace ElectricalEnergyMeasurement {
 
+struct MeasurementData
+{
+    Structs::MeasurementAccuracyStruct::Type measurementAccuracy;
+    Optional<Structs::EnergyMeasurementStruct::Type> cumulativeImported;
+    Optional<Structs::EnergyMeasurementStruct::Type> cumulativeExported;
+    Optional<Structs::EnergyMeasurementStruct::Type> periodicImported;
+    Optional<Structs::EnergyMeasurementStruct::Type> periodicExported;
+};
+
 bool NotifyCumulativeEnergyMeasured(EndpointId endpointId, const Optional<Structs::EnergyMeasurementStruct::Type> & energyImported,
                                     const Optional<Structs::EnergyMeasurementStruct::Type> & energyExported);
 
@@ -34,6 +43,8 @@
 
 CHIP_ERROR SetMeasurementAccuracy(EndpointId endpointId, const Structs::MeasurementAccuracyStruct::Type & accuracy);
 
+MeasurementData * MeasurementDataForEndpoint(EndpointId endpointId);
+
 } // namespace ElectricalEnergyMeasurement
 } // namespace Clusters
 } // namespace app
diff --git a/src/controller/python/chip/clusters/__init__.py b/src/controller/python/chip/clusters/__init__.py
index 1e4fcee..47a53ef 100644
--- a/src/controller/python/chip/clusters/__init__.py
+++ b/src/controller/python/chip/clusters/__init__.py
@@ -28,8 +28,8 @@
                       BinaryInputBasic, Binding, BooleanState, BooleanStateConfiguration, BridgedDeviceBasicInformation,
                       CarbonDioxideConcentrationMeasurement, CarbonMonoxideConcentrationMeasurement, Channel, ColorControl,
                       ContentLauncher, Descriptor, DeviceEnergyManagement, DeviceEnergyManagementMode, DiagnosticLogs,
-                      DishwasherAlarm, DishwasherMode, DoorLock, ElectricalMeasurement, EnergyEvse, EnergyEvseMode,
-                      EthernetNetworkDiagnostics, FanControl, FaultInjection, FixedLabel, FlowMeasurement,
+                      DishwasherAlarm, DishwasherMode, DoorLock, ElectricalEnergyMeasurement, ElectricalMeasurement, EnergyEvse,
+                      EnergyEvseMode, EthernetNetworkDiagnostics, FanControl, FaultInjection, FixedLabel, FlowMeasurement,
                       FormaldehydeConcentrationMeasurement, GeneralCommissioning, GeneralDiagnostics, GroupKeyManagement, Groups,
                       HepaFilterMonitoring, IcdManagement, Identify, IlluminanceMeasurement, KeypadInput, LaundryDryerControls,
                       LaundryWasherControls, LaundryWasherMode, LevelControl, LocalizationConfiguration, LowPower, MediaInput,
@@ -52,7 +52,7 @@
            BinaryInputBasic, Binding, BooleanState, BooleanStateConfiguration, BridgedDeviceBasicInformation, CarbonDioxideConcentrationMeasurement,
            CarbonMonoxideConcentrationMeasurement, Channel,
            ColorControl, ContentLauncher, Descriptor, DeviceEnergyManagementMode, DeviceEnergyManagement, DiagnosticLogs, DishwasherAlarm, DishwasherMode,
-           DoorLock, ElectricalMeasurement,  EnergyEvse, EnergyEvseMode, EthernetNetworkDiagnostics, FanControl, FaultInjection, FixedLabel, FlowMeasurement,
+           DoorLock, ElectricalMeasurement, ElectricalEnergyMeasurement,  EnergyEvse, EnergyEvseMode, EthernetNetworkDiagnostics, FanControl, FaultInjection, FixedLabel, FlowMeasurement,
            FormaldehydeConcentrationMeasurement, GeneralCommissioning, GeneralDiagnostics, GroupKeyManagement, Groups,
            HepaFilterMonitoring, IcdManagement, Identify, IlluminanceMeasurement, KeypadInput, LaundryDryerControls,
            LaundryWasherControls, LaundryWasherMode, LevelControl, LocalizationConfiguration, LowPower, MediaInput, MediaPlayback, MicrowaveOvenControl,