Skip to content

Commit

Permalink
[ESP32] Fix build and crash and add DeviceManagementCluster, EVSE mod…
Browse files Browse the repository at this point in the history
…e and DeviceManagementCluster mode. (#31591)

* [ESP32] Fix build failure and Add DeviceEnergyManagement clusters initialization

* Fix crash

* Support EVSE and Device Energy Management Mode

* Sync esp32 with linux app
  • Loading branch information
jadhavrohit924 authored and pull[bot] committed Feb 8, 2024
1 parent 94781af commit 1382428
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 28 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/examples-esp32.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,6 @@ jobs:

- name: Build example Lighting App (external platform)
run: scripts/examples/esp_example.sh lighting-app sdkconfig.ext_plat.defaults

- name: Build example Energy Management App
run: scripts/examples/esp_example.sh energy-management-app sdkconfig.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ CHIP_ERROR EnergyEvseManager::LoadPersistentAttributes()
{

SafeAttributePersistenceProvider * aProvider = GetSafeAttributePersistenceProvider();
EndpointId aEndpointId = mDelegate->GetEndpointId();
if (aProvider == nullptr)
{
ChipLogError(AppServer, "GetSafeAttributePersistenceProvider returned NULL");
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}
EndpointId aEndpointId = mDelegate->GetEndpointId();
CHIP_ERROR err;

// Restore ChargingEnabledUntil value
Expand Down
2 changes: 2 additions & 0 deletions examples/energy-management-app/esp32/main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ set(SRC_DIRS_LIST
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/time-format-localization-server"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/barrier-control-server"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/energy-evse-server"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/device-energy-management-server"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/network-commissioning"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/occupancy-sensor-server"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/operational-credentials-server"
Expand All @@ -63,6 +64,7 @@ set(SRC_DIRS_LIST
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/ota-requestor"
"${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"
)

set(PRIV_REQUIRES_LIST chip QRCode bt led_strip app_update openthread driver nvs_flash spi_flash)
Expand Down
256 changes: 229 additions & 27 deletions examples/energy-management-app/esp32/main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
*/

#include "DeviceCallbacks.h"
#include <DeviceEnergyManagementManager.h>
#include <EVSEManufacturerImpl.h>
#include <EnergyEvseManager.h>
#include <EnergyManagementManager.h>
#include <device-energy-management-modes.h>
#include <energy-evse-modes.h>

#include "esp_log.h"
#include <common/CHIPDeviceManager.h>
Expand Down Expand Up @@ -74,9 +77,11 @@ using namespace ::chip::Credentials;
using namespace ::chip::DeviceManager;
using namespace ::chip::DeviceLayer;

static EnergyEvseDelegate * gDelegate = nullptr;
static EnergyEvseManager * gInstance = nullptr;
static EVSEManufacturer * gEvseManufacturer = nullptr;
static std::unique_ptr<EnergyEvseDelegate> gEvseDelegate;
static std::unique_ptr<EnergyEvseManager> gEvseInstance;
static std::unique_ptr<DeviceEnergyManagementDelegate> gDEMDelegate;
static std::unique_ptr<DeviceEnergyManagementManager> gDEMInstance;
static std::unique_ptr<EVSEManufacturer> gEvseManufacturer;

#if CONFIG_ENABLE_ESP_INSIGHTS_TRACE
extern const char insights_auth_key_start[] asm("_binary_insights_auth_key_txt_start");
Expand Down Expand Up @@ -116,44 +121,238 @@ chip::Credentials::DeviceAttestationCredentialsProvider * get_dac_provider(void)

} // namespace

void ApplicationInit()
EVSEManufacturer * EnergyEvse::GetEvseManufacturer()
{
return gEvseManufacturer.get();
}

/*
* @brief Creates a Delegate and Instance for DEM
*
* The Instance is a container around the Delegate, so
* create the Delegate first, then wrap it in the Instance
* Then call the Instance->Init() to register the attribute and command handlers
*/
CHIP_ERROR DeviceEnergyManagementInit()
{
if (gDEMDelegate || gDEMInstance)
{
ESP_LOGE(TAG, "DEM Instance or Delegate already exist.");
return CHIP_ERROR_INCORRECT_STATE;
}

gDEMDelegate = std::make_unique<DeviceEnergyManagementDelegate>();
if (!gDEMDelegate)
{
ESP_LOGE(TAG, "Failed to allocate memory for DeviceEnergyManagementDelegate");
return CHIP_ERROR_NO_MEMORY;
}

/* Manufacturer may optionally not support all features, commands & attributes */
gDEMInstance = std::make_unique<DeviceEnergyManagementManager>(
EndpointId(ENERGY_EVSE_ENDPOINT), *gDEMDelegate,
BitMask<DeviceEnergyManagement::Feature, uint32_t>(
DeviceEnergyManagement::Feature::kPowerAdjustment, DeviceEnergyManagement::Feature::kPowerForecastReporting,
DeviceEnergyManagement::Feature::kStateForecastReporting, DeviceEnergyManagement::Feature::kStartTimeAdjustment,
DeviceEnergyManagement::Feature::kPausable, DeviceEnergyManagement::Feature::kForecastAdjustment,
DeviceEnergyManagement::Feature::kConstraintBasedAdjustment));

if (!gDEMInstance)
{
ESP_LOGE(TAG, "Failed to allocate memory for DeviceEnergyManagementManager");
gDEMDelegate.reset();
return CHIP_ERROR_NO_MEMORY;
}

CHIP_ERROR err = gDEMInstance->Init(); /* Register Attribute & Command handlers */
if (err != CHIP_NO_ERROR)
{
ESP_LOGE(TAG, "Init failed on gDEMInstance, err:%" CHIP_ERROR_FORMAT, err.Format());
gDEMInstance.reset();
gDEMDelegate.reset();
return err;
}

return CHIP_NO_ERROR;
}

CHIP_ERROR DeviceEnergyManagementShutdown()
{
if ((gDelegate == nullptr) && (gInstance == nullptr) && (gEvseManufacturer == nullptr))
/* Do this in the order Instance first, then delegate
* Ensure we call the Instance->Shutdown to free attribute & command handlers first
*/
if (gDEMInstance)
{
gDelegate = new EnergyEvseDelegate();
if (gDelegate != nullptr)
{
gInstance = new EnergyEvseManager(
EndpointId(ENERGY_EVSE_ENDPOINT), *gDelegate,
BitMask<EnergyEvse::Feature, uint32_t>(EnergyEvse::Feature::kChargingPreferences,
EnergyEvse::Feature::kPlugAndCharge, EnergyEvse::Feature::kRfid,
EnergyEvse::Feature::kSoCReporting, EnergyEvse::Feature::kV2x),
BitMask<OptionalAttributes, uint32_t>(OptionalAttributes::kSupportsUserMaximumChargingCurrent,
OptionalAttributes::kSupportsRandomizationWindow,
OptionalAttributes::kSupportsApproximateEvEfficiency),
BitMask<OptionalCommands, uint32_t>(OptionalCommands::kSupportsStartDiagnostics));
gInstance->Init(); /* Register Attribute & Command handlers */
}
/* deregister attribute & command handlers */
gDEMInstance->Shutdown();
gDEMInstance.reset();
}
else
if (gDEMDelegate)
{
ChipLogError(AppServer, "EVSE Instance or Delegate already exist.")
gDEMDelegate.reset();
}
return CHIP_NO_ERROR;
}

/*
* @brief Creates a Delegate and Instance for EVSE cluster
*
* The Instance is a container around the Delegate, so
* create the Delegate first, then wrap it in the Instance
* Then call the Instance->Init() to register the attribute and command handlers
*/
CHIP_ERROR EnergyEvseInit()
{
CHIP_ERROR err;

if (gEvseManufacturer == nullptr)
if (gEvseDelegate || gEvseInstance)
{
gEvseManufacturer = new EVSEManufacturer();
gEvseManufacturer->Init(gInstance);
ESP_LOGE(TAG, "EVSE Instance or Delegate already exist.");
return CHIP_ERROR_INCORRECT_STATE;
}
else

gEvseDelegate = std::make_unique<EnergyEvseDelegate>();
if (!gEvseDelegate)
{
ESP_LOGE(TAG, "Failed to allocate memory for EnergyEvseDelegate");
return CHIP_ERROR_NO_MEMORY;
}

/* Manufacturer may optionally not support all features, commands & attributes */
gEvseInstance = std::make_unique<EnergyEvseManager>(
EndpointId(ENERGY_EVSE_ENDPOINT), *gEvseDelegate,
BitMask<EnergyEvse::Feature, uint32_t>(EnergyEvse::Feature::kChargingPreferences, EnergyEvse::Feature::kPlugAndCharge,
EnergyEvse::Feature::kRfid, EnergyEvse::Feature::kSoCReporting,
EnergyEvse::Feature::kV2x),
BitMask<EnergyEvse::OptionalAttributes, uint32_t>(EnergyEvse::OptionalAttributes::kSupportsUserMaximumChargingCurrent,
EnergyEvse::OptionalAttributes::kSupportsRandomizationWindow,
EnergyEvse::OptionalAttributes::kSupportsApproximateEvEfficiency),
BitMask<EnergyEvse::OptionalCommands, uint32_t>(EnergyEvse::OptionalCommands::kSupportsStartDiagnostics));

if (!gEvseInstance)
{
ChipLogError(AppServer, "EVSEManufacturer already exists.")
ESP_LOGE(TAG, "Failed to allocate memory for EnergyEvseManager");
gEvseDelegate.reset();
return CHIP_ERROR_NO_MEMORY;
}

err = gEvseInstance->Init(); /* Register Attribute & Command handlers */
if (err != CHIP_NO_ERROR)
{
ESP_LOGE(TAG, "Init failed on gEvseInstance, err:%" CHIP_ERROR_FORMAT, err.Format());
gEvseInstance.reset();
gEvseDelegate.reset();
return err;
}

return CHIP_NO_ERROR;
}

CHIP_ERROR EnergyEvseShutdown()
{
/* Do this in the order Instance first, then delegate
* Ensure we call the Instance->Shutdown to free attribute & command handlers first
*/
if (gEvseInstance)
{
/* deregister attribute & command handlers */
gEvseInstance->Shutdown();
gEvseInstance.reset();
}

if (gEvseDelegate)
{
gEvseDelegate.reset();
}

return CHIP_NO_ERROR;
}

/*
* @brief Creates a EVSEManufacturer class to hold the EVSE & DEM clusters
*
* The Instance is a container around the Delegate, so
* create the Delegate first, then wrap it in the Instance
* Then call the Instance->Init() to register the attribute and command handlers
*/
CHIP_ERROR EVSEManufacturerInit()
{
CHIP_ERROR err;

if (gEvseManufacturer)
{
ESP_LOGE(TAG, "EvseManufacturer already exist.");
return CHIP_ERROR_INCORRECT_STATE;
}

/* Now create EVSEManufacturer */
gEvseManufacturer = std::make_unique<EVSEManufacturer>(gEvseInstance.get());
if (!gEvseManufacturer)
{
ESP_LOGE(TAG, "Failed to allocate memory for EvseManufacturer");
return CHIP_ERROR_NO_MEMORY;
}

/* Call Manufacturer specific init */
err = gEvseManufacturer->Init();
if (err != CHIP_NO_ERROR)
{
ESP_LOGE(TAG, "Init failed on gEvseManufacturer, err:%" CHIP_ERROR_FORMAT, err.Format());
gEvseManufacturer.reset();
return err;
}

return CHIP_NO_ERROR;
}

CHIP_ERROR EVSEManufacturerShutdown()
{
if (gEvseManufacturer)
{
/* Shutdown the EVSEManufacturer */
gEvseManufacturer->Shutdown();
gEvseManufacturer.reset();
}

return CHIP_NO_ERROR;
}

void ApplicationInit()
{
if (DeviceEnergyManagementInit() != CHIP_NO_ERROR)
{
return;
}

if (EnergyEvseInit() != CHIP_NO_ERROR)
{
DeviceEnergyManagementShutdown();
return;
}

if (EVSEManufacturerInit() != CHIP_NO_ERROR)
{
DeviceEnergyManagementShutdown();
EnergyEvseShutdown();
return;
}
}

void ApplicationShutdown()
{
ESP_LOGD(TAG, "Energy Management App: ApplicationShutdown()");

/* Shutdown in reverse order that they were created */
EVSEManufacturerShutdown(); /* Free the EVSEManufacturer */
EnergyEvseShutdown(); /* Free the EnergyEvse */
DeviceEnergyManagementShutdown(); /* Free the DEM */

Clusters::DeviceEnergyManagementMode::Shutdown();
Clusters::EnergyEvseMode::Shutdown();
}

static void InitServer(intptr_t context)
{
ApplicationInit();
// Print QR Code URL
PrintOnboardingCodes(chip::RendezvousInformationFlags(CONFIG_RENDEZVOUS_MODE));

Expand All @@ -175,6 +374,9 @@ static void InitServer(intptr_t context)
static Tracing::Insights::ESP32Backend backend;
Tracing::Register(backend);
#endif

// Application code should always be initialised after the initialisation of server.
ApplicationInit();
}

extern "C" void app_main()
Expand Down

0 comments on commit 1382428

Please sign in to comment.