EVSE Delegate callbacks to user application (#30999)

* Fix #30665 (EVSE)
- Changed to use amperage_mA, energy_mWh
- removed max on epoch_s
- removed access for operate
- removed side for events

* Fix #30665 updates to try to get further with ZAP and autogen, but still fails with some parts of regen_all

* Added ember-compatibility-functions.cpp which was missing.

* Made all types all lowercase to resolve regen_all issues.

* Fixed lint issue (trailing whitespace).

* Fixes #30727 - Added initial EVSE cluster and Example Energy Managament app.

* Tidied up old comments.

* Restyled by whitespace

* Restyled by gn

* Restyled by prettier-markdown

* Added copy of files to all-clusters-app linux BUILD.gn and did basic test with chip-tool

* Fixed lint error (Remove PRId64)

* Fix for Documentation Build and publish checker.

* Updated all-clusters-app.zap after merge and regen_all

* Added Cluster to ESP32 CMakeLists.txt

* Fixed ESP32 compile error caused by %d

* Added missing source files to each build variant

* Restyled by gn

* Fixed incorrect uint64_t in EnableCharging/EnableDischarging command

* Fixed more issues seen on different platforms

* Removed unused mEndpointId

* Add source files to shell standalone BUILD.gn,  More %d fixes for different platforms

* Restyled by gn

* Removed unused mMinimumChargingCurrentLimitFromCommand

* Removed yet more unused variables

* Fixed missing semi-colon. How did the other compilers not pick this up?

* Capitalise function names

* PR comment - Moved PluginServerInitCallback to sdk. Capitalised more function names in energy-management-app.

* Restyled by whitespace

* Fixes #30805 Updated energy-evse-cluster.xml

* Fixes #30805 zap_regen_all commit.

* Made Fault Event allow a nullable SessionID

* Updates based on review (use kMaximumChargeCurrent instead of duplicate #define). Add HwSetVehicleID implementation

* Added RFID Event support. Removed more unnecessary chip::

* Added Feature flags, optional commands and optional attributes.

* Made command handling conditional based on features

* Added Feature support to all-clusters-app

* Restyled by clang-format

* Fix to Darwin compile error - not checking strcmp return

* Attempt to fix Darwin errors (return after else)

* Updated based on latest upstream master

* Removed unnecessary mInstance and used 'this' instead.

* Regen_all after merge to master.

* Fix review comment.

* Ensure Init() returns a failure if there is one. Aligned to mode-base-server.cpp

* Backed out Read attr check based on features.

* Fixed EnumerateAcceptedCommands to handle Loop::Break condition.

* Had missed StartDiagnostic as an optional command in InvokeCommand

* Removed extra chip:: in attr types.

* Updated HwSetVehicleID to copy the value from callee

* Fixed potential buffer overrun in HwSetVehicleID.

* Fixed simple to address comments raised by Andrei in PR 30857

* Fixed simple to address comments raised by Andrei in PR 30857

* Check Delegate is initialized before calling functions.

* Check Delegate is initialized before calling functions.

* Added callbacks into Application code

* Restyled by whitespace

* Ensured that mVehicleID free's any malloc'd CharSpan in destructor

* Sync EnergyEvseDelegateImpl.cpp from Example Energy Management

* Ensured that mVehicleID free's any malloc'd CharSpan in destructor

* Sync EnergyEvseDelegateImpl.cpp from Example Energy Management

* Sync'd changes from example energy management app, and commits from #30857 & #30727

* Added namespace to avoid global namespace error in header file.

* Re-write of ApplicationInit to handle potential errors

* Re-write of ApplicationInit to handle potential errors

* Removed unnecessary void in function decl.

* Open and saved in ZAP, then regen_all

* Updated Energy-management-app.zap / .matter after change to general-diagnostics.xml change to MS.

* Updated Energy-management-app.zap / .matter after change to general-diagnostics.xml change to MS.

* Restyled by whitespace

* Fixed types to be signed=true

* Fixed 31032 - revert removal of side="server". Also turned on Events.

* PR comment fix - remove Localization Config and Time Format Localization cluster

* Removed EVSE commands from ZAP to avoid emberAf linker errors since these are handled in the IM Commands handler

* Regen_all to update energy-management.matter file to remove commands that cause linker errors.

* Minor changes to align all-clusters and energy-management common.

* Apply suggestions from code review

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

* Addressed comment and replicated into example energy management copies.

* Added documentation to EVSE Callbacks as to which struct in the union is used.

* Added Energy EVSE and Device Energy Management to config-data.yml under CommandHandlerInterfaceOnlyClusters. Then turned on EVSE commands in ZAP.

---------

Co-authored-by: Restyled.io <commits@restyled.io>
Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter
index 45be7ed..59090b6 100644
--- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter
+++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter
@@ -7354,6 +7354,15 @@
     callback attribute attributeList;
     ram      attribute featureMap default = 0;
     ram      attribute clusterRevision default = 2;
+
+    handle command GetTargetsResponse;
+    handle command Disable;
+    handle command EnableCharging;
+    handle command EnableDischarging;
+    handle command StartDiagnostics;
+    handle command SetTargets;
+    handle command GetTargets;
+    handle command ClearTargets;
   }
 
   server cluster WindowCovering {
diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap
index 0bba4b8..6f35331 100644
--- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap
+++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap
@@ -11737,6 +11737,72 @@
           "side": "server",
           "enabled": 1,
           "apiMaturity": "provisional",
+          "commands": [
+            {
+              "name": "GetTargetsResponse",
+              "code": 0,
+              "mfgCode": null,
+              "source": "server",
+              "isIncoming": 0,
+              "isEnabled": 1
+            },
+            {
+              "name": "Disable",
+              "code": 1,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            },
+            {
+              "name": "EnableCharging",
+              "code": 2,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            },
+            {
+              "name": "EnableDischarging",
+              "code": 3,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            },
+            {
+              "name": "StartDiagnostics",
+              "code": 4,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            },
+            {
+              "name": "SetTargets",
+              "code": 5,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            },
+            {
+              "name": "GetTargets",
+              "code": 6,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            },
+            {
+              "name": "ClearTargets",
+              "code": 7,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            }
+          ],
           "attributes": [
             {
               "name": "State",
diff --git a/examples/all-clusters-app/all-clusters-common/include/EVSECallbacks.h b/examples/all-clusters-app/all-clusters-common/include/EVSECallbacks.h
new file mode 100644
index 0000000..5bdac2f
--- /dev/null
+++ b/examples/all-clusters-app/all-clusters-common/include/EVSECallbacks.h
@@ -0,0 +1,84 @@
+/*
+ *
+ *    Copyright (c) 2023 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    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
+
+namespace chip {
+namespace app {
+namespace Clusters {
+
+using namespace chip::app::Clusters::EnergyEvse;
+
+/* This callbacks mechanism is intended to allow different delegates to
+ * dispatch notifications that something has changed.
+ *
+ * This is not specific to the EnergyEVSE cluster, but includes DeviceEnergyManagement
+ * and potential future clusters.
+ */
+enum EVSECallbackType
+{
+    /*
+     * The State has changed (e.g. from Disabled to Charging, or vice-versa)
+     */
+    StateChanged,
+    /*
+     * ChargeCurrent has changed
+     */
+    ChargeCurrentChanged,
+    /*
+     * Charging Preferences have changed
+     */
+    ChargingPreferencesChanged,
+    /*
+     * DeviceEnergyManagement has changed
+     */
+    DeviceEnergyManagementChanged,
+};
+
+struct EVSECbInfo
+{
+    EVSECallbackType type;
+
+    union
+    {
+        /* for type = StateChanged */
+        struct
+        {
+            StateEnum state;
+            SupplyStateEnum supplyState;
+        } StateChange;
+
+        /* for type = ChargeCurrentChanged */
+        struct
+        {
+            int64_t maximumChargeCurrent;
+        } ChargingCurrent;
+    };
+};
+
+typedef void (*EVSECallbackFunc)(const EVSECbInfo * cb, intptr_t arg);
+
+struct EVSECallbackWrapper
+{
+    EVSECallbackFunc handler;
+    intptr_t arg;
+};
+
+} // namespace Clusters
+} // namespace app
+} // namespace chip
diff --git a/examples/all-clusters-app/all-clusters-common/include/EnergyEvseDelegateImpl.h b/examples/all-clusters-app/all-clusters-common/include/EnergyEvseDelegateImpl.h
index 0a967e2..f3c003d 100644
--- a/examples/all-clusters-app/all-clusters-common/include/EnergyEvseDelegateImpl.h
+++ b/examples/all-clusters-app/all-clusters-common/include/EnergyEvseDelegateImpl.h
@@ -19,6 +19,7 @@
 #pragma once
 
 #include "app/clusters/energy-evse-server/energy-evse-server.h"
+#include <EVSECallbacks.h>
 
 #include <app/util/af.h>
 #include <app/util/config.h>
@@ -68,9 +69,13 @@
      */
     Status StartDiagnostics() override;
 
+    /**
+     * @brief    Called by EVSE Hardware to register a single callback handler
+     */
+    Status HwRegisterEvseCallbackHandler(EVSECallbackFunc handler, intptr_t arg);
+
     // -----------------------------------------------------------------
     // Internal API to allow an EVSE to change its internal state etc
-    // TODO Status HwRegisterEvseHardwareCallback(Callback);
     Status HwSetMaxHardwareCurrentLimit(int64_t currentmA);
     Status HwSetCircuitCapacity(int64_t currentmA);
     Status HwSetCableAssemblyLimit(int64_t currentmA);
@@ -150,6 +155,11 @@
     int64_t mActualChargingCurrentLimit             = 0;
     StateEnum mHwState                              = StateEnum::kNotPluggedIn; /* Hardware state */
 
+    /* Callback related */
+    EVSECallbackWrapper mCallbacks = { .handler = nullptr, .arg = 0 }; /* Wrapper to allow callbacks to be registered */
+    Status NotifyApplicationCurrentLimitChange(int64_t maximumChargeCurrent);
+    Status NotifyApplicationStateChange();
+
     /**
      * @brief Helper function to work out the charge limit based on conditions and settings
      */
diff --git a/examples/all-clusters-app/all-clusters-common/src/EnergyEvseDelegateImpl.cpp b/examples/all-clusters-app/all-clusters-common/src/EnergyEvseDelegateImpl.cpp
index 64d8b98..4cc83ea 100644
--- a/examples/all-clusters-app/all-clusters-common/src/EnergyEvseDelegateImpl.cpp
+++ b/examples/all-clusters-app/all-clusters-common/src/EnergyEvseDelegateImpl.cpp
@@ -83,6 +83,7 @@
     /* update MaximumDischargeCurrent to 0 */
     SetMaximumDischargeCurrent(0);
 
+    NotifyApplicationStateChange();
     // TODO: Generate events
 
     return Status::Success;
@@ -102,31 +103,31 @@
 
     if (maximumChargeCurrent < kMinimumChargeCurrent || maximumChargeCurrent > kMaximumChargeCurrent)
     {
-        ChipLogError(NotSpecified, "Maximum Current outside limits");
+        ChipLogError(AppServer, "Maximum Current outside limits");
         return Status::ConstraintError;
     }
 
     if (minimumChargeCurrent < kMinimumChargeCurrent || minimumChargeCurrent > kMaximumChargeCurrent)
     {
-        ChipLogError(NotSpecified, "Maximum Current outside limits");
+        ChipLogError(AppServer, "Maximum Current outside limits");
         return Status::ConstraintError;
     }
 
     if (minimumChargeCurrent > maximumChargeCurrent)
     {
-        ChipLogError(NotSpecified, "Minium Current > Maximum Current!");
+        ChipLogError(AppServer, "Minium Current > Maximum Current!");
         return Status::ConstraintError;
     }
 
     if (chargingEnabledUntil.IsNull())
     {
         /* Charging enabled indefinitely */
-        ChipLogError(NotSpecified, "Charging enabled indefinitely");
+        ChipLogError(AppServer, "Charging enabled indefinitely");
     }
     else
     {
         /* check chargingEnabledUntil is in the future */
-        ChipLogError(NotSpecified, "Charging enabled until: %lu", static_cast<long unsigned int>(chargingEnabledUntil.Value()));
+        ChipLogError(AppServer, "Charging enabled until: %lu", static_cast<long unsigned int>(chargingEnabledUntil.Value()));
         // TODO
         // if (checkChargingEnabled)
     }
@@ -169,6 +170,8 @@
 
     // TODO: Generate events
 
+    NotifyApplicationStateChange();
+
     return this->ComputeMaxChargeCurrentLimit();
 }
 
@@ -188,6 +191,8 @@
 
     // TODO: Generate events
 
+    NotifyApplicationStateChange();
+
     return Status::Success;
 }
 
@@ -199,27 +204,44 @@
     /* For EVSE manufacturers to customize */
     ChipLogProgress(AppServer, "EnergyEvseDelegate::StartDiagnostics()");
 
-    /* update SupplyState */
+    /* update SupplyState to indicate we are now in Diagnostics mode */
     SetSupplyState(SupplyStateEnum::kDisabledDiagnostics);
 
     // TODO: Generate events
 
+    // TODO: Notify Application to implement Diagnostics
+
+    NotifyApplicationStateChange();
+
     return Status::Success;
 }
 
 /* ---------------------------------------------------------------------------
- * FUNCTIONS BELOW:
- *    - EVSE Hardware interface
- *
- *  SetMaxHardwareCurrentLimit( currentmA )
- *  SetCircuitCapacity( currentmA )
- *  SetCableAssemblyLimit( currentmA )
- *  SetState( EVSEStateEnum )
- *  SetFault
- *
+ *  EVSE Hardware interface below
  */
 
 /**
+ * @brief    Called by EVSE Hardware to register a callback handler mechanism
+ *
+ *           This is normally called at start-up.
+ *
+ * @param    EVSECallbackFunct - function pointer to call
+ * @param    intptr_t          - optional context to provide back to callback handler
+ */
+Status EnergyEvseDelegate::HwRegisterEvseCallbackHandler(EVSECallbackFunc handler, intptr_t arg)
+{
+    if (mCallbacks.handler != nullptr)
+    {
+        ChipLogError(AppServer, "Callback handler already initialized");
+        return Status::Failure;
+    }
+    mCallbacks.handler = handler;
+    mCallbacks.arg     = arg;
+
+    return Status::Success;
+}
+
+/**
  * @brief    Called by EVSE Hardware to notify the delegate of the maximum
  *           current limit supported by the hardware.
  *
@@ -420,17 +442,18 @@
 
 /**
  *  @brief   Called to compute the safe charging current limit
+ *
+ * mActualChargingCurrentLimit is the minimum of:
+ *   - MaxHardwareCurrentLimit (of the hardware)
+ *   - CircuitCapacity (set by the electrician - less than the hardware)
+ *   - CableAssemblyLimit (detected when the cable is inserted)
+ *   - MaximumChargeCurrent (from charging command)
+ *   - UserMaximumChargeCurrent (could dynamically change)
+ *
  */
 Status EnergyEvseDelegate::ComputeMaxChargeCurrentLimit()
 {
     int64_t oldValue;
-    /* mActualChargingCurrentLimit is the minimum of:
-     *   - MaxHardwareCurrentLimit (of the hardware)
-     *   - CircuitCapacity (set by the electrician - less than the hardware)
-     *   - CableAssemblyLimit (detected when the cable is inserted)
-     *   - MaximumChargeCurrent (from charging command)
-     *   - UserMaximumChargeCurrent (could dynamically change)
-     */
 
     oldValue                    = mActualChargingCurrentLimit;
     mActualChargingCurrentLimit = mMaxHardwareCurrentLimit;
@@ -448,11 +471,42 @@
         MatterReportingAttributeChangeCallback(mEndpointId, EnergyEvse::Id, MaximumChargeCurrent::Id);
 
         /* Call the EV Charger hardware current limit callback */
-        // TODO
+        NotifyApplicationCurrentLimitChange(mMaximumChargeCurrent);
     }
     return Status::Success;
 }
 
+Status EnergyEvseDelegate::NotifyApplicationCurrentLimitChange(int64_t maximumChargeCurrent)
+{
+    EVSECbInfo cbInfo;
+
+    cbInfo.type                                 = EVSECallbackType::ChargeCurrentChanged;
+    cbInfo.ChargingCurrent.maximumChargeCurrent = maximumChargeCurrent;
+
+    if (mCallbacks.handler != nullptr)
+    {
+        mCallbacks.handler(&cbInfo, mCallbacks.arg);
+    }
+
+    return Status::Success;
+}
+
+Status EnergyEvseDelegate::NotifyApplicationStateChange()
+{
+    EVSECbInfo cbInfo;
+
+    cbInfo.type                    = EVSECallbackType::StateChanged;
+    cbInfo.StateChange.state       = mState;
+    cbInfo.StateChange.supplyState = mSupplyState;
+
+    if (mCallbacks.handler != nullptr)
+    {
+        mCallbacks.handler(&cbInfo, mCallbacks.arg);
+    }
+
+    return Status::Success;
+}
+
 /**
  * Attribute methods
  */
diff --git a/examples/energy-management-app/energy-management-common/include/EVSECallbacks.h b/examples/energy-management-app/energy-management-common/include/EVSECallbacks.h
new file mode 100644
index 0000000..5bdac2f
--- /dev/null
+++ b/examples/energy-management-app/energy-management-common/include/EVSECallbacks.h
@@ -0,0 +1,84 @@
+/*
+ *
+ *    Copyright (c) 2023 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    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
+
+namespace chip {
+namespace app {
+namespace Clusters {
+
+using namespace chip::app::Clusters::EnergyEvse;
+
+/* This callbacks mechanism is intended to allow different delegates to
+ * dispatch notifications that something has changed.
+ *
+ * This is not specific to the EnergyEVSE cluster, but includes DeviceEnergyManagement
+ * and potential future clusters.
+ */
+enum EVSECallbackType
+{
+    /*
+     * The State has changed (e.g. from Disabled to Charging, or vice-versa)
+     */
+    StateChanged,
+    /*
+     * ChargeCurrent has changed
+     */
+    ChargeCurrentChanged,
+    /*
+     * Charging Preferences have changed
+     */
+    ChargingPreferencesChanged,
+    /*
+     * DeviceEnergyManagement has changed
+     */
+    DeviceEnergyManagementChanged,
+};
+
+struct EVSECbInfo
+{
+    EVSECallbackType type;
+
+    union
+    {
+        /* for type = StateChanged */
+        struct
+        {
+            StateEnum state;
+            SupplyStateEnum supplyState;
+        } StateChange;
+
+        /* for type = ChargeCurrentChanged */
+        struct
+        {
+            int64_t maximumChargeCurrent;
+        } ChargingCurrent;
+    };
+};
+
+typedef void (*EVSECallbackFunc)(const EVSECbInfo * cb, intptr_t arg);
+
+struct EVSECallbackWrapper
+{
+    EVSECallbackFunc handler;
+    intptr_t arg;
+};
+
+} // namespace Clusters
+} // namespace app
+} // namespace chip
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 34e9027..4ff45e9 100644
--- a/examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h
+++ b/examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h
@@ -43,6 +43,11 @@
      */
     CHIP_ERROR Shutdown(EnergyEvseManager * aInstance);
 
+    /**
+     * @brief   Main Callback handler from delegate to user code
+     */
+    static void ApplicationCallbackHandler(const EVSECbInfo * cb, intptr_t arg);
+
 private:
 };
 
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 0a967e2..f3c003d 100644
--- a/examples/energy-management-app/energy-management-common/include/EnergyEvseDelegateImpl.h
+++ b/examples/energy-management-app/energy-management-common/include/EnergyEvseDelegateImpl.h
@@ -19,6 +19,7 @@
 #pragma once
 
 #include "app/clusters/energy-evse-server/energy-evse-server.h"
+#include <EVSECallbacks.h>
 
 #include <app/util/af.h>
 #include <app/util/config.h>
@@ -68,9 +69,13 @@
      */
     Status StartDiagnostics() override;
 
+    /**
+     * @brief    Called by EVSE Hardware to register a single callback handler
+     */
+    Status HwRegisterEvseCallbackHandler(EVSECallbackFunc handler, intptr_t arg);
+
     // -----------------------------------------------------------------
     // Internal API to allow an EVSE to change its internal state etc
-    // TODO Status HwRegisterEvseHardwareCallback(Callback);
     Status HwSetMaxHardwareCurrentLimit(int64_t currentmA);
     Status HwSetCircuitCapacity(int64_t currentmA);
     Status HwSetCableAssemblyLimit(int64_t currentmA);
@@ -150,6 +155,11 @@
     int64_t mActualChargingCurrentLimit             = 0;
     StateEnum mHwState                              = StateEnum::kNotPluggedIn; /* Hardware state */
 
+    /* Callback related */
+    EVSECallbackWrapper mCallbacks = { .handler = nullptr, .arg = 0 }; /* Wrapper to allow callbacks to be registered */
+    Status NotifyApplicationCurrentLimitChange(int64_t maximumChargeCurrent);
+    Status NotifyApplicationStateChange();
+
     /**
      * @brief Helper function to work out the charge limit based on conditions and settings
      */
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 e5ad193..8daf178 100644
--- a/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp
+++ b/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp
@@ -35,7 +35,7 @@
         return CHIP_ERROR_UNINITIALIZED;
     }
 
-    // TODO EnergyEvseManager::GetInstance()->GetDelegate()->RegisterCallbacks();
+    dg->HwRegisterEvseCallbackHandler(ApplicationCallbackHandler, reinterpret_cast<intptr_t>(nullptr));
 
     /* Set the EVSE Hardware Maximum current limit */
     // For Manufacturer to specify the hardware capability in mA
@@ -67,3 +67,27 @@
 
     return CHIP_NO_ERROR;
 }
+
+/**
+ * @brief    Main Callback handler - to be implemented by Manufacturer
+ *
+ * @param    EVSECbInfo describes the type of call back, and a union of structs
+ *           which contain relevant info for the specific callback type
+ *
+ * @param    arg - optional pointer to some context information (see register function)
+ */
+void EVSEManufacturer::ApplicationCallbackHandler(const EVSECbInfo * cb, intptr_t arg)
+{
+    switch (cb->type)
+    {
+    case EVSECallbackType::StateChanged:
+        ChipLogProgress(AppServer, "EVSE callback - state changed");
+        break;
+    case EVSECallbackType::ChargeCurrentChanged:
+        ChipLogProgress(AppServer, "EVSE callback - maxChargeCurrent changed to %ld",
+                        static_cast<long>(cb->ChargingCurrent.maximumChargeCurrent));
+        break;
+    default:
+        ChipLogError(AppServer, "Unhandler EVSE Callback type %d", static_cast<int>(cb->type));
+    }
+}
diff --git a/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp b/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp
index 7ad16c3..4cc83ea 100644
--- a/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp
+++ b/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp
@@ -48,7 +48,7 @@
 {
     ChipLogProgress(AppServer, "EnergyEvseDelegate::Disable()");
 
-    /* update State */
+    /* Update State */
     switch (mHwState)
     {
     case StateEnum::kNotPluggedIn:
@@ -83,6 +83,7 @@
     /* update MaximumDischargeCurrent to 0 */
     SetMaximumDischargeCurrent(0);
 
+    NotifyApplicationStateChange();
     // TODO: Generate events
 
     return Status::Success;
@@ -102,31 +103,31 @@
 
     if (maximumChargeCurrent < kMinimumChargeCurrent || maximumChargeCurrent > kMaximumChargeCurrent)
     {
-        ChipLogError(NotSpecified, "Maximum Current outside limits");
+        ChipLogError(AppServer, "Maximum Current outside limits");
         return Status::ConstraintError;
     }
 
     if (minimumChargeCurrent < kMinimumChargeCurrent || minimumChargeCurrent > kMaximumChargeCurrent)
     {
-        ChipLogError(NotSpecified, "Maximum Current outside limits");
+        ChipLogError(AppServer, "Maximum Current outside limits");
         return Status::ConstraintError;
     }
 
     if (minimumChargeCurrent > maximumChargeCurrent)
     {
-        ChipLogError(NotSpecified, "Minium Current > Maximum Current!");
+        ChipLogError(AppServer, "Minium Current > Maximum Current!");
         return Status::ConstraintError;
     }
 
     if (chargingEnabledUntil.IsNull())
     {
         /* Charging enabled indefinitely */
-        ChipLogError(NotSpecified, "Charging enabled indefinitely");
+        ChipLogError(AppServer, "Charging enabled indefinitely");
     }
     else
     {
         /* check chargingEnabledUntil is in the future */
-        ChipLogError(NotSpecified, "Charging enabled until: %lu", static_cast<long unsigned int>(chargingEnabledUntil.Value()));
+        ChipLogError(AppServer, "Charging enabled until: %lu", static_cast<long unsigned int>(chargingEnabledUntil.Value()));
         // TODO
         // if (checkChargingEnabled)
     }
@@ -169,6 +170,8 @@
 
     // TODO: Generate events
 
+    NotifyApplicationStateChange();
+
     return this->ComputeMaxChargeCurrentLimit();
 }
 
@@ -188,6 +191,8 @@
 
     // TODO: Generate events
 
+    NotifyApplicationStateChange();
+
     return Status::Success;
 }
 
@@ -199,27 +204,44 @@
     /* For EVSE manufacturers to customize */
     ChipLogProgress(AppServer, "EnergyEvseDelegate::StartDiagnostics()");
 
-    /* update SupplyState */
+    /* update SupplyState to indicate we are now in Diagnostics mode */
     SetSupplyState(SupplyStateEnum::kDisabledDiagnostics);
 
     // TODO: Generate events
 
+    // TODO: Notify Application to implement Diagnostics
+
+    NotifyApplicationStateChange();
+
     return Status::Success;
 }
 
 /* ---------------------------------------------------------------------------
- * FUNCTIONS BELOW:
- *    - EVSE Hardware interface
- *
- *  SetMaxHardwareCurrentLimit( currentmA )
- *  SetCircuitCapacity( currentmA )
- *  SetCableAssemblyLimit( currentmA )
- *  SetState( EVSEStateEnum )
- *  SetFault
- *
+ *  EVSE Hardware interface below
  */
 
 /**
+ * @brief    Called by EVSE Hardware to register a callback handler mechanism
+ *
+ *           This is normally called at start-up.
+ *
+ * @param    EVSECallbackFunct - function pointer to call
+ * @param    intptr_t          - optional context to provide back to callback handler
+ */
+Status EnergyEvseDelegate::HwRegisterEvseCallbackHandler(EVSECallbackFunc handler, intptr_t arg)
+{
+    if (mCallbacks.handler != nullptr)
+    {
+        ChipLogError(AppServer, "Callback handler already initialized");
+        return Status::Failure;
+    }
+    mCallbacks.handler = handler;
+    mCallbacks.arg     = arg;
+
+    return Status::Success;
+}
+
+/**
  * @brief    Called by EVSE Hardware to notify the delegate of the maximum
  *           current limit supported by the hardware.
  *
@@ -420,17 +442,18 @@
 
 /**
  *  @brief   Called to compute the safe charging current limit
+ *
+ * mActualChargingCurrentLimit is the minimum of:
+ *   - MaxHardwareCurrentLimit (of the hardware)
+ *   - CircuitCapacity (set by the electrician - less than the hardware)
+ *   - CableAssemblyLimit (detected when the cable is inserted)
+ *   - MaximumChargeCurrent (from charging command)
+ *   - UserMaximumChargeCurrent (could dynamically change)
+ *
  */
 Status EnergyEvseDelegate::ComputeMaxChargeCurrentLimit()
 {
     int64_t oldValue;
-    /* mActualChargingCurrentLimit is the minimum of:
-     *   - MaxHardwareCurrentLimit (of the hardware)
-     *   - CircuitCapacity (set by the electrician - less than the hardware)
-     *   - CableAssemblyLimit (detected when the cable is inserted)
-     *   - MaximumChargeCurrent (from charging command)
-     *   - UserMaximumChargeCurrent (could dynamically change)
-     */
 
     oldValue                    = mActualChargingCurrentLimit;
     mActualChargingCurrentLimit = mMaxHardwareCurrentLimit;
@@ -448,11 +471,42 @@
         MatterReportingAttributeChangeCallback(mEndpointId, EnergyEvse::Id, MaximumChargeCurrent::Id);
 
         /* Call the EV Charger hardware current limit callback */
-        // TODO
+        NotifyApplicationCurrentLimitChange(mMaximumChargeCurrent);
     }
     return Status::Success;
 }
 
+Status EnergyEvseDelegate::NotifyApplicationCurrentLimitChange(int64_t maximumChargeCurrent)
+{
+    EVSECbInfo cbInfo;
+
+    cbInfo.type                                 = EVSECallbackType::ChargeCurrentChanged;
+    cbInfo.ChargingCurrent.maximumChargeCurrent = maximumChargeCurrent;
+
+    if (mCallbacks.handler != nullptr)
+    {
+        mCallbacks.handler(&cbInfo, mCallbacks.arg);
+    }
+
+    return Status::Success;
+}
+
+Status EnergyEvseDelegate::NotifyApplicationStateChange()
+{
+    EVSECbInfo cbInfo;
+
+    cbInfo.type                    = EVSECallbackType::StateChanged;
+    cbInfo.StateChange.state       = mState;
+    cbInfo.StateChange.supplyState = mSupplyState;
+
+    if (mCallbacks.handler != nullptr)
+    {
+        mCallbacks.handler(&cbInfo, mCallbacks.arg);
+    }
+
+    return Status::Success;
+}
+
 /**
  * Attribute methods
  */
diff --git a/src/app/common/templates/config-data.yaml b/src/app/common/templates/config-data.yaml
index 9d3e094..577e04a 100644
--- a/src/app/common/templates/config-data.yaml
+++ b/src/app/common/templates/config-data.yaml
@@ -37,6 +37,8 @@
     - RVC Operational State
     - Sample MEI
     - Microwave Oven Control
+    - Energy EVSE
+    - Device Energy Management
 
 # We need a more configurable way of deciding which clusters have which init functions....
 # See https://github.com/project-chip/connectedhomeip/issues/4369
diff --git a/zzz_generated/app-common/app-common/zap-generated/callback.h b/zzz_generated/app-common/app-common/zap-generated/callback.h
index c37f234..439ed6b 100644
--- a/zzz_generated/app-common/app-common/zap-generated/callback.h
+++ b/zzz_generated/app-common/app-common/zap-generated/callback.h
@@ -10238,90 +10238,6 @@
     chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
     const chip::app::Clusters::DemandResponseLoadControl::Commands::ClearLoadControlEventsRequest::DecodableType & commandData);
 /**
- * @brief Device Energy Management Cluster PowerAdjustRequest Command callback (from client)
- */
-bool emberAfDeviceEnergyManagementClusterPowerAdjustRequestCallback(
-    chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
-    const chip::app::Clusters::DeviceEnergyManagement::Commands::PowerAdjustRequest::DecodableType & commandData);
-/**
- * @brief Device Energy Management Cluster CancelPowerAdjustRequest Command callback (from client)
- */
-bool emberAfDeviceEnergyManagementClusterCancelPowerAdjustRequestCallback(
-    chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
-    const chip::app::Clusters::DeviceEnergyManagement::Commands::CancelPowerAdjustRequest::DecodableType & commandData);
-/**
- * @brief Device Energy Management Cluster StartTimeAdjustRequest Command callback (from client)
- */
-bool emberAfDeviceEnergyManagementClusterStartTimeAdjustRequestCallback(
-    chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
-    const chip::app::Clusters::DeviceEnergyManagement::Commands::StartTimeAdjustRequest::DecodableType & commandData);
-/**
- * @brief Device Energy Management Cluster PauseRequest Command callback (from client)
- */
-bool emberAfDeviceEnergyManagementClusterPauseRequestCallback(
-    chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
-    const chip::app::Clusters::DeviceEnergyManagement::Commands::PauseRequest::DecodableType & commandData);
-/**
- * @brief Device Energy Management Cluster ResumeRequest Command callback (from client)
- */
-bool emberAfDeviceEnergyManagementClusterResumeRequestCallback(
-    chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
-    const chip::app::Clusters::DeviceEnergyManagement::Commands::ResumeRequest::DecodableType & commandData);
-/**
- * @brief Device Energy Management Cluster ModifyForecastRequest Command callback (from client)
- */
-bool emberAfDeviceEnergyManagementClusterModifyForecastRequestCallback(
-    chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
-    const chip::app::Clusters::DeviceEnergyManagement::Commands::ModifyForecastRequest::DecodableType & commandData);
-/**
- * @brief Device Energy Management Cluster RequestConstraintBasedForecast Command callback (from client)
- */
-bool emberAfDeviceEnergyManagementClusterRequestConstraintBasedForecastCallback(
-    chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
-    const chip::app::Clusters::DeviceEnergyManagement::Commands::RequestConstraintBasedForecast::DecodableType & commandData);
-/**
- * @brief Energy EVSE Cluster Disable Command callback (from client)
- */
-bool emberAfEnergyEvseClusterDisableCallback(chip::app::CommandHandler * commandObj,
-                                             const chip::app::ConcreteCommandPath & commandPath,
-                                             const chip::app::Clusters::EnergyEvse::Commands::Disable::DecodableType & commandData);
-/**
- * @brief Energy EVSE Cluster EnableCharging Command callback (from client)
- */
-bool emberAfEnergyEvseClusterEnableChargingCallback(
-    chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
-    const chip::app::Clusters::EnergyEvse::Commands::EnableCharging::DecodableType & commandData);
-/**
- * @brief Energy EVSE Cluster EnableDischarging Command callback (from client)
- */
-bool emberAfEnergyEvseClusterEnableDischargingCallback(
-    chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
-    const chip::app::Clusters::EnergyEvse::Commands::EnableDischarging::DecodableType & commandData);
-/**
- * @brief Energy EVSE Cluster StartDiagnostics Command callback (from client)
- */
-bool emberAfEnergyEvseClusterStartDiagnosticsCallback(
-    chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
-    const chip::app::Clusters::EnergyEvse::Commands::StartDiagnostics::DecodableType & commandData);
-/**
- * @brief Energy EVSE Cluster SetTargets Command callback (from client)
- */
-bool emberAfEnergyEvseClusterSetTargetsCallback(
-    chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
-    const chip::app::Clusters::EnergyEvse::Commands::SetTargets::DecodableType & commandData);
-/**
- * @brief Energy EVSE Cluster GetTargets Command callback (from client)
- */
-bool emberAfEnergyEvseClusterGetTargetsCallback(
-    chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
-    const chip::app::Clusters::EnergyEvse::Commands::GetTargets::DecodableType & commandData);
-/**
- * @brief Energy EVSE Cluster ClearTargets Command callback (from client)
- */
-bool emberAfEnergyEvseClusterClearTargetsCallback(
-    chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
-    const chip::app::Clusters::EnergyEvse::Commands::ClearTargets::DecodableType & commandData);
-/**
  * @brief Door Lock Cluster LockDoor Command callback (from client)
  */
 bool emberAfDoorLockClusterLockDoorCallback(chip::app::CommandHandler * commandObj,