Skip to content

Commit be8dccb

Browse files
[ESP32] Fix build and crash and add DeviceManagementCluster, EVSE mode and DeviceManagementCluster mode. (project-chip#31591)
* [ESP32] Fix build failure and Add DeviceEnergyManagement clusters initialization * Fix crash * Support EVSE and Device Energy Management Mode * Sync esp32 with linux app
1 parent 53d3b3a commit be8dccb

File tree

4 files changed

+240
-28
lines changed

4 files changed

+240
-28
lines changed

.github/workflows/examples-esp32.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,6 @@ jobs:
165165

166166
- name: Build example Lighting App (external platform)
167167
run: scripts/examples/esp_example.sh lighting-app sdkconfig.ext_plat.defaults
168+
169+
- name: Build example Energy Management App
170+
run: scripts/examples/esp_example.sh energy-management-app sdkconfig.defaults

examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,12 @@ CHIP_ERROR EnergyEvseManager::LoadPersistentAttributes()
2727
{
2828

2929
SafeAttributePersistenceProvider * aProvider = GetSafeAttributePersistenceProvider();
30-
EndpointId aEndpointId = mDelegate->GetEndpointId();
30+
if (aProvider == nullptr)
31+
{
32+
ChipLogError(AppServer, "GetSafeAttributePersistenceProvider returned NULL");
33+
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
34+
}
35+
EndpointId aEndpointId = mDelegate->GetEndpointId();
3136
CHIP_ERROR err;
3237

3338
// Restore ChargingEnabledUntil value

examples/energy-management-app/esp32/main/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ set(SRC_DIRS_LIST
5050
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/time-format-localization-server"
5151
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/barrier-control-server"
5252
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/energy-evse-server"
53+
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/device-energy-management-server"
5354
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/network-commissioning"
5455
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/occupancy-sensor-server"
5556
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/operational-credentials-server"
@@ -63,6 +64,7 @@ set(SRC_DIRS_LIST
6364
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/ota-requestor"
6465
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/groups-server"
6566
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/group-key-mgmt-server"
67+
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/mode-base-server"
6668
)
6769

6870
set(PRIV_REQUIRES_LIST chip QRCode bt led_strip app_update openthread driver nvs_flash spi_flash)

examples/energy-management-app/esp32/main/main.cpp

+229-27
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616
*/
1717

1818
#include "DeviceCallbacks.h"
19+
#include <DeviceEnergyManagementManager.h>
1920
#include <EVSEManufacturerImpl.h>
2021
#include <EnergyEvseManager.h>
2122
#include <EnergyManagementManager.h>
23+
#include <device-energy-management-modes.h>
24+
#include <energy-evse-modes.h>
2225

2326
#include "esp_log.h"
2427
#include <common/CHIPDeviceManager.h>
@@ -74,9 +77,11 @@ using namespace ::chip::Credentials;
7477
using namespace ::chip::DeviceManager;
7578
using namespace ::chip::DeviceLayer;
7679

77-
static EnergyEvseDelegate * gDelegate = nullptr;
78-
static EnergyEvseManager * gInstance = nullptr;
79-
static EVSEManufacturer * gEvseManufacturer = nullptr;
80+
static std::unique_ptr<EnergyEvseDelegate> gEvseDelegate;
81+
static std::unique_ptr<EnergyEvseManager> gEvseInstance;
82+
static std::unique_ptr<DeviceEnergyManagementDelegate> gDEMDelegate;
83+
static std::unique_ptr<DeviceEnergyManagementManager> gDEMInstance;
84+
static std::unique_ptr<EVSEManufacturer> gEvseManufacturer;
8085

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

117122
} // namespace
118123

119-
void ApplicationInit()
124+
EVSEManufacturer * EnergyEvse::GetEvseManufacturer()
125+
{
126+
return gEvseManufacturer.get();
127+
}
128+
129+
/*
130+
* @brief Creates a Delegate and Instance for DEM
131+
*
132+
* The Instance is a container around the Delegate, so
133+
* create the Delegate first, then wrap it in the Instance
134+
* Then call the Instance->Init() to register the attribute and command handlers
135+
*/
136+
CHIP_ERROR DeviceEnergyManagementInit()
137+
{
138+
if (gDEMDelegate || gDEMInstance)
139+
{
140+
ESP_LOGE(TAG, "DEM Instance or Delegate already exist.");
141+
return CHIP_ERROR_INCORRECT_STATE;
142+
}
143+
144+
gDEMDelegate = std::make_unique<DeviceEnergyManagementDelegate>();
145+
if (!gDEMDelegate)
146+
{
147+
ESP_LOGE(TAG, "Failed to allocate memory for DeviceEnergyManagementDelegate");
148+
return CHIP_ERROR_NO_MEMORY;
149+
}
150+
151+
/* Manufacturer may optionally not support all features, commands & attributes */
152+
gDEMInstance = std::make_unique<DeviceEnergyManagementManager>(
153+
EndpointId(ENERGY_EVSE_ENDPOINT), *gDEMDelegate,
154+
BitMask<DeviceEnergyManagement::Feature, uint32_t>(
155+
DeviceEnergyManagement::Feature::kPowerAdjustment, DeviceEnergyManagement::Feature::kPowerForecastReporting,
156+
DeviceEnergyManagement::Feature::kStateForecastReporting, DeviceEnergyManagement::Feature::kStartTimeAdjustment,
157+
DeviceEnergyManagement::Feature::kPausable, DeviceEnergyManagement::Feature::kForecastAdjustment,
158+
DeviceEnergyManagement::Feature::kConstraintBasedAdjustment));
159+
160+
if (!gDEMInstance)
161+
{
162+
ESP_LOGE(TAG, "Failed to allocate memory for DeviceEnergyManagementManager");
163+
gDEMDelegate.reset();
164+
return CHIP_ERROR_NO_MEMORY;
165+
}
166+
167+
CHIP_ERROR err = gDEMInstance->Init(); /* Register Attribute & Command handlers */
168+
if (err != CHIP_NO_ERROR)
169+
{
170+
ESP_LOGE(TAG, "Init failed on gDEMInstance, err:%" CHIP_ERROR_FORMAT, err.Format());
171+
gDEMInstance.reset();
172+
gDEMDelegate.reset();
173+
return err;
174+
}
175+
176+
return CHIP_NO_ERROR;
177+
}
178+
179+
CHIP_ERROR DeviceEnergyManagementShutdown()
120180
{
121-
if ((gDelegate == nullptr) && (gInstance == nullptr) && (gEvseManufacturer == nullptr))
181+
/* Do this in the order Instance first, then delegate
182+
* Ensure we call the Instance->Shutdown to free attribute & command handlers first
183+
*/
184+
if (gDEMInstance)
122185
{
123-
gDelegate = new EnergyEvseDelegate();
124-
if (gDelegate != nullptr)
125-
{
126-
gInstance = new EnergyEvseManager(
127-
EndpointId(ENERGY_EVSE_ENDPOINT), *gDelegate,
128-
BitMask<EnergyEvse::Feature, uint32_t>(EnergyEvse::Feature::kChargingPreferences,
129-
EnergyEvse::Feature::kPlugAndCharge, EnergyEvse::Feature::kRfid,
130-
EnergyEvse::Feature::kSoCReporting, EnergyEvse::Feature::kV2x),
131-
BitMask<OptionalAttributes, uint32_t>(OptionalAttributes::kSupportsUserMaximumChargingCurrent,
132-
OptionalAttributes::kSupportsRandomizationWindow,
133-
OptionalAttributes::kSupportsApproximateEvEfficiency),
134-
BitMask<OptionalCommands, uint32_t>(OptionalCommands::kSupportsStartDiagnostics));
135-
gInstance->Init(); /* Register Attribute & Command handlers */
136-
}
186+
/* deregister attribute & command handlers */
187+
gDEMInstance->Shutdown();
188+
gDEMInstance.reset();
137189
}
138-
else
190+
if (gDEMDelegate)
139191
{
140-
ChipLogError(AppServer, "EVSE Instance or Delegate already exist.")
192+
gDEMDelegate.reset();
141193
}
194+
return CHIP_NO_ERROR;
195+
}
196+
197+
/*
198+
* @brief Creates a Delegate and Instance for EVSE cluster
199+
*
200+
* The Instance is a container around the Delegate, so
201+
* create the Delegate first, then wrap it in the Instance
202+
* Then call the Instance->Init() to register the attribute and command handlers
203+
*/
204+
CHIP_ERROR EnergyEvseInit()
205+
{
206+
CHIP_ERROR err;
142207

143-
if (gEvseManufacturer == nullptr)
208+
if (gEvseDelegate || gEvseInstance)
144209
{
145-
gEvseManufacturer = new EVSEManufacturer();
146-
gEvseManufacturer->Init(gInstance);
210+
ESP_LOGE(TAG, "EVSE Instance or Delegate already exist.");
211+
return CHIP_ERROR_INCORRECT_STATE;
147212
}
148-
else
213+
214+
gEvseDelegate = std::make_unique<EnergyEvseDelegate>();
215+
if (!gEvseDelegate)
216+
{
217+
ESP_LOGE(TAG, "Failed to allocate memory for EnergyEvseDelegate");
218+
return CHIP_ERROR_NO_MEMORY;
219+
}
220+
221+
/* Manufacturer may optionally not support all features, commands & attributes */
222+
gEvseInstance = std::make_unique<EnergyEvseManager>(
223+
EndpointId(ENERGY_EVSE_ENDPOINT), *gEvseDelegate,
224+
BitMask<EnergyEvse::Feature, uint32_t>(EnergyEvse::Feature::kChargingPreferences, EnergyEvse::Feature::kPlugAndCharge,
225+
EnergyEvse::Feature::kRfid, EnergyEvse::Feature::kSoCReporting,
226+
EnergyEvse::Feature::kV2x),
227+
BitMask<EnergyEvse::OptionalAttributes, uint32_t>(EnergyEvse::OptionalAttributes::kSupportsUserMaximumChargingCurrent,
228+
EnergyEvse::OptionalAttributes::kSupportsRandomizationWindow,
229+
EnergyEvse::OptionalAttributes::kSupportsApproximateEvEfficiency),
230+
BitMask<EnergyEvse::OptionalCommands, uint32_t>(EnergyEvse::OptionalCommands::kSupportsStartDiagnostics));
231+
232+
if (!gEvseInstance)
149233
{
150-
ChipLogError(AppServer, "EVSEManufacturer already exists.")
234+
ESP_LOGE(TAG, "Failed to allocate memory for EnergyEvseManager");
235+
gEvseDelegate.reset();
236+
return CHIP_ERROR_NO_MEMORY;
151237
}
238+
239+
err = gEvseInstance->Init(); /* Register Attribute & Command handlers */
240+
if (err != CHIP_NO_ERROR)
241+
{
242+
ESP_LOGE(TAG, "Init failed on gEvseInstance, err:%" CHIP_ERROR_FORMAT, err.Format());
243+
gEvseInstance.reset();
244+
gEvseDelegate.reset();
245+
return err;
246+
}
247+
248+
return CHIP_NO_ERROR;
249+
}
250+
251+
CHIP_ERROR EnergyEvseShutdown()
252+
{
253+
/* Do this in the order Instance first, then delegate
254+
* Ensure we call the Instance->Shutdown to free attribute & command handlers first
255+
*/
256+
if (gEvseInstance)
257+
{
258+
/* deregister attribute & command handlers */
259+
gEvseInstance->Shutdown();
260+
gEvseInstance.reset();
261+
}
262+
263+
if (gEvseDelegate)
264+
{
265+
gEvseDelegate.reset();
266+
}
267+
268+
return CHIP_NO_ERROR;
269+
}
270+
271+
/*
272+
* @brief Creates a EVSEManufacturer class to hold the EVSE & DEM clusters
273+
*
274+
* The Instance is a container around the Delegate, so
275+
* create the Delegate first, then wrap it in the Instance
276+
* Then call the Instance->Init() to register the attribute and command handlers
277+
*/
278+
CHIP_ERROR EVSEManufacturerInit()
279+
{
280+
CHIP_ERROR err;
281+
282+
if (gEvseManufacturer)
283+
{
284+
ESP_LOGE(TAG, "EvseManufacturer already exist.");
285+
return CHIP_ERROR_INCORRECT_STATE;
286+
}
287+
288+
/* Now create EVSEManufacturer */
289+
gEvseManufacturer = std::make_unique<EVSEManufacturer>(gEvseInstance.get());
290+
if (!gEvseManufacturer)
291+
{
292+
ESP_LOGE(TAG, "Failed to allocate memory for EvseManufacturer");
293+
return CHIP_ERROR_NO_MEMORY;
294+
}
295+
296+
/* Call Manufacturer specific init */
297+
err = gEvseManufacturer->Init();
298+
if (err != CHIP_NO_ERROR)
299+
{
300+
ESP_LOGE(TAG, "Init failed on gEvseManufacturer, err:%" CHIP_ERROR_FORMAT, err.Format());
301+
gEvseManufacturer.reset();
302+
return err;
303+
}
304+
305+
return CHIP_NO_ERROR;
306+
}
307+
308+
CHIP_ERROR EVSEManufacturerShutdown()
309+
{
310+
if (gEvseManufacturer)
311+
{
312+
/* Shutdown the EVSEManufacturer */
313+
gEvseManufacturer->Shutdown();
314+
gEvseManufacturer.reset();
315+
}
316+
317+
return CHIP_NO_ERROR;
318+
}
319+
320+
void ApplicationInit()
321+
{
322+
if (DeviceEnergyManagementInit() != CHIP_NO_ERROR)
323+
{
324+
return;
325+
}
326+
327+
if (EnergyEvseInit() != CHIP_NO_ERROR)
328+
{
329+
DeviceEnergyManagementShutdown();
330+
return;
331+
}
332+
333+
if (EVSEManufacturerInit() != CHIP_NO_ERROR)
334+
{
335+
DeviceEnergyManagementShutdown();
336+
EnergyEvseShutdown();
337+
return;
338+
}
339+
}
340+
341+
void ApplicationShutdown()
342+
{
343+
ESP_LOGD(TAG, "Energy Management App: ApplicationShutdown()");
344+
345+
/* Shutdown in reverse order that they were created */
346+
EVSEManufacturerShutdown(); /* Free the EVSEManufacturer */
347+
EnergyEvseShutdown(); /* Free the EnergyEvse */
348+
DeviceEnergyManagementShutdown(); /* Free the DEM */
349+
350+
Clusters::DeviceEnergyManagementMode::Shutdown();
351+
Clusters::EnergyEvseMode::Shutdown();
152352
}
153353

154354
static void InitServer(intptr_t context)
155355
{
156-
ApplicationInit();
157356
// Print QR Code URL
158357
PrintOnboardingCodes(chip::RendezvousInformationFlags(CONFIG_RENDEZVOUS_MODE));
159358

@@ -175,6 +374,9 @@ static void InitServer(intptr_t context)
175374
static Tracing::Insights::ESP32Backend backend;
176375
Tracing::Register(backend);
177376
#endif
377+
378+
// Application code should always be initialised after the initialisation of server.
379+
ApplicationInit();
178380
}
179381

180382
extern "C" void app_main()

0 commit comments

Comments
 (0)