Skip to content

Commit 4abbe28

Browse files
jamesharrowrestyled-commitsbzbarsky-apple
authored
EVSE add Session and Event support, test event trigger support (#31200)
* Beginnings of Session handling * Added beginnings of EVConnected,EVNotDetected,EnergyTransferStarted,EnergyTransferStopped handling. State machine is not finished. Callback to read Energy Meter added * Added framework for EVSE Test Event triggers * Added EnergyEvseTestEventTrigger delegates * Restyled by whitespace * Restyled by gn * Added :energy-evse-test-event-trigger to public_deps to see if it resolves build errors * Restyled by gn * Fixed Darwin compile error - do not use else after return * Refactored code so that the EvseManufacturer instance could be retrieved for Test Event triggers * Started adding TC_EEVSE_2_2.py * Updated TC_EEVSE_2_2.py to support test events. Still needs to handle reading of Logged Events and verifying they are correct. * Refactored Handling of TestEvents to allow clear, and better error handling. * Refactored state handling by decomposing into state machine events where similar functions are performed based on state transition. Fixed TC chargingEnabledUntil cast to int. Note gets to step 6e * Fixed step 6e caused by not setting the cable limit / maxHardwareCurrentLimit in test events * Added comment to clarify purpose and definition of test eventtrigger field values. * Fixed several bugs in test script * Made SetChargingEnabledUntil take a nullable type. * Removed Reference to step 5c, and moved reading of SessionID to step 4b. More TC_EEVSE_2_2 bug fixes. Added event checking. Still fails at step 14. Does not have enable timeout timer implemented * Fixed issue with not detecting 2nd plug in event, and session ID not incrementing. Now test case passes all the way. * Restyled by isort * Made some attributes persisted per spec. * Fixed incorrect type - not picked up by all compilers. * Added provisional handling for Faults * Added new test event triggers to help test Fault and Diagnostics * Added TC_EEVSE_2_4 * Fix lint issue - unused datetime modules. * Added TC_EEVSE_2_5.py to support DiagnosticsCommand testing. Also changed the SupplyState reverting to Disabled once diagnostics is complete to match the spec. * Created a helper EEVSE base class to avoid repetition in the different test cases. * Restyled by isort * Fixed Lint issues * Revamped TC_EEVSE_2_5 to match spec behaviour (cannot start diagnostics unless Disabled). Also removed hard-coded endpoint ids in Utils * Implemented timer to disable the EVSE automatically. * Added documentation to cover concern about long-lived bytespan in enableKey * Fixed Lint and build issues on other platforms * Restyled by isort * Implemented some of the feedback on PR * Refactored HwSetState to use nested switch statements to be clear that all enums are caught. * Fixed error messages * Test scripts: Removed hardcoded endpoint 1 (use --endpoint 1 in args), allowed the enableKey to be passed in using --hex-arg enableKey:000102030405060708090a0b0c0d0e0f * Made enum class for callbacks and improved documentation comments based on feedback. * Fixed another python lint issue. * Updated README.md with help on how to build for test event triggers, using chip-repl and python testing. * Tweaks to README.md to avoid Myst syntax highlighting issues. * Improved error logging around GetEpochTS() * Made main use std::unique_ptr instead of using new/delete per PR comments. Also moved GetEVSEManufacturer declaration to header file. * Fixing MISSPELL issues in README.md * Fixes #31061 Updated DEVICE_TYPE to 0x050C now this has been allocated * Small correction to description in test case. * Update examples/energy-management-app/energy-management-common/include/EnergyEvseDelegateImpl.h Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> * Touched file to retrigger restyled job * Removed whitespace which was added to trigger restyled to rerun --------- Co-authored-by: Restyled.io <commits@restyled.io> Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
1 parent c4f7024 commit 4abbe28

22 files changed

+2788
-226
lines changed

.github/.wordlist.txt

+2
Original file line numberDiff line numberDiff line change
@@ -519,8 +519,10 @@ EthyleneOxideConcentrationMeasurement
519519
EvalCode
520520
EvalCodeWithName
521521
EvalFrameDefault
522+
EV
522523
EVB
523524
evk
525+
EVSE
524526
exceptfds
525527
ExchangeContext
526528
exe

examples/energy-management-app/energy-management-common/include/EVSECallbacks.h

+25-3
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,41 @@ using namespace chip::app::Clusters::EnergyEvse;
3030
* This is not specific to the EnergyEVSE cluster, but includes DeviceEnergyManagement
3131
* and potential future clusters.
3232
*/
33-
enum EVSECallbackType
33+
enum class EVSECallbackType : uint8_t
3434
{
3535
/*
3636
* The State has changed (e.g. from Disabled to Charging, or vice-versa)
3737
*/
3838
StateChanged,
3939
/*
40-
* ChargeCurrent has changed
40+
* ChargeCurrent has changed (e.g. maxChargingCurrent so requires an
41+
update to advertise a different charging current to the EV)
4142
*/
4243
ChargeCurrentChanged,
4344
/*
4445
* Charging Preferences have changed
46+
* The daily charging target time, SoC / Added Energy schedules have changed
47+
* and may require the local optimiser to re-run.
4548
*/
4649
ChargingPreferencesChanged,
4750
/*
48-
* DeviceEnergyManagement has changed
51+
* Energy Meter Reading requested from the hardware, e.g. so that the session
52+
* information can be updated.
53+
*/
54+
EnergyMeterReadingRequested,
55+
/*
56+
* The associated DeviceEnergyManagement cluster has changed. This may mean
57+
* that the start time, or power profile or power levels have been adjusted
4958
*/
5059
DeviceEnergyManagementChanged,
5160
};
5261

62+
enum class ChargingDischargingType : uint8_t
63+
{
64+
kCharging,
65+
kDischarging
66+
};
67+
5368
struct EVSECbInfo
5469
{
5570
EVSECallbackType type;
@@ -68,6 +83,13 @@ struct EVSECbInfo
6883
{
6984
int64_t maximumChargeCurrent;
7085
} ChargingCurrent;
86+
87+
/* for type = EnergyMeterReadingRequested */
88+
struct
89+
{
90+
ChargingDischargingType meterType;
91+
int64_t * energyMeterValuePtr;
92+
} EnergyMeterReadingRequest;
7193
};
7294
};
7395

examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h

+28-2
Original file line numberDiff line numberDiff line change
@@ -33,24 +33,50 @@ namespace EnergyEvse {
3333
class EVSEManufacturer
3434
{
3535
public:
36+
EVSEManufacturer(EnergyEvseManager * aInstance) { mInstance = aInstance; }
37+
EnergyEvseManager * GetInstance() { return mInstance; }
38+
EnergyEvseDelegate * GetDelegate()
39+
{
40+
if (mInstance)
41+
{
42+
return mInstance->GetDelegate();
43+
}
44+
return nullptr;
45+
}
46+
3647
/**
3748
* @brief Called at start up to apply hardware settings
3849
*/
39-
CHIP_ERROR Init(EnergyEvseManager * aInstance);
50+
CHIP_ERROR Init();
4051

4152
/**
4253
* @brief Called at shutdown
4354
*/
44-
CHIP_ERROR Shutdown(EnergyEvseManager * aInstance);
55+
CHIP_ERROR Shutdown();
4556

4657
/**
4758
* @brief Main Callback handler from delegate to user code
4859
*/
4960
static void ApplicationCallbackHandler(const EVSECbInfo * cb, intptr_t arg);
5061

5162
private:
63+
EnergyEvseManager * mInstance;
64+
65+
int64_t mLastChargingEnergyMeter = 0;
66+
int64_t mLastDischargingEnergyMeter = 0;
5267
};
5368

69+
/** @brief Helper function to return the singleton EVSEManufacturer instance
70+
*
71+
* This is needed by the EVSEManufacturer class to support TestEventTriggers
72+
* which are called outside of any class context. This allows the EVSEManufacturer
73+
* class to return the relevant Delegate instance in which to invoke the test
74+
* events on.
75+
*
76+
* This function is typically found in main.cpp or wherever the singleton is created.
77+
*/
78+
EVSEManufacturer * GetEvseManufacturer();
79+
5480
} // namespace EnergyEvse
5581
} // namespace Clusters
5682
} // namespace app

examples/energy-management-app/energy-management-common/include/EnergyEvseDelegateImpl.h

+130-15
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,68 @@ namespace app {
3131
namespace Clusters {
3232
namespace EnergyEvse {
3333

34+
/* Local state machine Events to allow simpler handling of state transitions */
35+
enum EVSEStateMachineEvent
36+
{
37+
EVPluggedInEvent, /* EV has been plugged in */
38+
EVNotDetectedEvent, /* EV has been unplugged or detected as not connected */
39+
EVNoDemandEvent, /* EV has stopped asking for demand */
40+
EVDemandEvent, /* EV has asked for demand*/
41+
ChargingEnabledEvent, /* Charging has been enabled */
42+
DischargingEnabledEvent, /* Discharging has been enabled */
43+
DisabledEvent, /* EVSE has been disabled */
44+
FaultRaised, /* Fault has been raised */
45+
FaultCleared, /* Fault has been cleared */
46+
};
47+
48+
/**
49+
* Helper class to handle all of the session related info
50+
*/
51+
class EvseSession
52+
{
53+
public:
54+
EvseSession(EndpointId aEndpoint) { mEndpointId = aEndpoint; }
55+
/**
56+
* @brief This function records the start time and provided energy meter values as part of the new session.
57+
*
58+
* @param chargingMeterValue - The current value of the energy meter (charging) in mWh
59+
* @param dischargingMeterValue - The current value of the energy meter (discharging) in mWh
60+
*/
61+
void StartSession(int64_t chargingMeterValue, int64_t dischargingMeterValue);
62+
63+
/**
64+
* @brief This function updates the session Duration to allow read attributes to return latest values
65+
*/
66+
void RecalculateSessionDuration();
67+
68+
/**
69+
* @brief This function updates the EnergyCharged meter value
70+
*
71+
* @param chargingMeterValue - The value of the energy meter (charging) in mWh
72+
*/
73+
void UpdateEnergyCharged(int64_t chargingMeterValue);
74+
75+
/**
76+
* @brief This function updates the EnergyDischarged meter value
77+
*
78+
* @param dischargingMeterValue - The value of the energy meter (discharging) in mWh
79+
*/
80+
void UpdateEnergyDischarged(int64_t dischargingMeterValue);
81+
82+
/* Public members - represent attributes in the cluster */
83+
DataModel::Nullable<uint32_t> mSessionID;
84+
DataModel::Nullable<uint32_t> mSessionDuration;
85+
DataModel::Nullable<int64_t> mSessionEnergyCharged;
86+
DataModel::Nullable<int64_t> mSessionEnergyDischarged;
87+
88+
private:
89+
EndpointId mEndpointId = 0;
90+
91+
uint32_t mStartTime = 0; // Epoch_s - 0 means it hasn't started yet
92+
int64_t mSessionEnergyChargedAtStart = 0; // in mWh - 0 means it hasn't been set yet
93+
int64_t mSessionEnergyDischargedAtStart = 0; // in mWh - 0 means it hasn't been set yet
94+
};
95+
3496
/**
3597
* The application delegate.
3698
*/
@@ -74,15 +136,41 @@ class EnergyEvseDelegate : public EnergyEvse::Delegate
74136
*/
75137
Status HwRegisterEvseCallbackHandler(EVSECallbackFunc handler, intptr_t arg);
76138

139+
/**
140+
* @brief Decides if a timer is needed based on EVSE state and sets a callback if needed
141+
*
142+
* In order to ensure the EVSE restarts charging (if enabled) after power loss
143+
* this should be called after the EVSE is initialised
144+
* (e.g. HwSetMaxHardwareCurrentLimit and HwSetCircuitCapacity have been called)
145+
* and the persisted attributes have been loaded, and time has been synchronised.
146+
*
147+
* If time isn't sync'd yet it will call itself back periodically (if required)
148+
* until time is sync'd.
149+
*
150+
* It is also called when a EnableCharging or EnableDischarging command
151+
* is recv'd to schedule when the EVSE should be automatically disabled based
152+
* on ChargingEnabledUntil / DischargingEnabledUntil expiring.
153+
*/
154+
Status ScheduleCheckOnEnabledTimeout();
155+
77156
// -----------------------------------------------------------------
78157
// Internal API to allow an EVSE to change its internal state etc
79158
Status HwSetMaxHardwareCurrentLimit(int64_t currentmA);
159+
int64_t HwGetMaxHardwareCurrentLimit() { return mMaxHardwareCurrentLimit; }
80160
Status HwSetCircuitCapacity(int64_t currentmA);
81161
Status HwSetCableAssemblyLimit(int64_t currentmA);
162+
int64_t HwGetCableAssemblyLimit() { return mCableAssemblyCurrentLimit; }
82163
Status HwSetState(StateEnum state);
164+
StateEnum HwGetState() { return mHwState; };
83165
Status HwSetFault(FaultStateEnum fault);
84166
Status HwSetRFID(ByteSpan uid);
85167
Status HwSetVehicleID(const CharSpan & vehID);
168+
Status HwDiagnosticsComplete();
169+
Status SendEVConnectedEvent();
170+
Status SendEVNotDetectedEvent();
171+
Status SendEnergyTransferStartedEvent();
172+
Status SendEnergyTransferStoppedEvent(EnergyTransferStoppedReasonEnum reason);
173+
Status SendFaultEvent(FaultStateEnum newFaultState);
86174

87175
// ------------------------------------------------------------------
88176
// Get attribute methods
@@ -96,10 +184,10 @@ class EnergyEvseDelegate : public EnergyEvse::Delegate
96184
CHIP_ERROR SetFaultState(FaultStateEnum);
97185

98186
DataModel::Nullable<uint32_t> GetChargingEnabledUntil() override;
99-
CHIP_ERROR SetChargingEnabledUntil(uint32_t);
187+
CHIP_ERROR SetChargingEnabledUntil(DataModel::Nullable<uint32_t>);
100188

101189
DataModel::Nullable<uint32_t> GetDischargingEnabledUntil() override;
102-
CHIP_ERROR SetDischargingEnabledUntil(uint32_t);
190+
CHIP_ERROR SetDischargingEnabledUntil(DataModel::Nullable<uint32_t>);
103191

104192
int64_t GetCircuitCapacity() override;
105193
CHIP_ERROR SetCircuitCapacity(int64_t);
@@ -128,7 +216,7 @@ class EnergyEvseDelegate : public EnergyEvse::Delegate
128216
DataModel::Nullable<Percent> GetNextChargeTargetSoC() override;
129217

130218
DataModel::Nullable<uint16_t> GetApproximateEVEfficiency() override;
131-
CHIP_ERROR SetApproximateEVEfficiency(uint16_t) override;
219+
CHIP_ERROR SetApproximateEVEfficiency(DataModel::Nullable<uint16_t>) override;
132220

133221
/* SOC attributes */
134222
DataModel::Nullable<Percent> GetStateOfCharge() override;
@@ -143,10 +231,11 @@ class EnergyEvseDelegate : public EnergyEvse::Delegate
143231

144232
private:
145233
/* Constants */
146-
static constexpr int DEFAULT_MIN_CHARGE_CURRENT = 6000; /* 6A */
147-
static constexpr int DEFAULT_USER_MAXIMUM_CHARGE_CURRENT = kMaximumChargeCurrent; /* 80A */
148-
static constexpr int DEFAULT_RANDOMIZATION_DELAY_WINDOW = 600; /* 600s */
149-
static constexpr int kMaxVehicleIDBufSize = 32;
234+
static constexpr int kDefaultMinChargeCurrent = 6000; /* 6A */
235+
static constexpr int kDefaultUserMaximumChargeCurrent = kMaximumChargeCurrent; /* 80A */
236+
static constexpr int kDefaultRandomizationDelayWindow = 600; /* 600s */
237+
static constexpr int kMaxVehicleIDBufSize = 32;
238+
static constexpr int kPeriodicCheckIntervalRealTimeClockNotSynced = 30;
150239

151240
/* private variables for controlling the hardware - these are not attributes */
152241
int64_t mMaxHardwareCurrentLimit = 0; /* Hardware current limit in mA */
@@ -155,28 +244,54 @@ class EnergyEvseDelegate : public EnergyEvse::Delegate
155244
int64_t mActualChargingCurrentLimit = 0;
156245
StateEnum mHwState = StateEnum::kNotPluggedIn; /* Hardware state */
157246

247+
/* Variables to hold State and SupplyState in case a fault is raised */
248+
StateEnum mStateBeforeFault = StateEnum::kUnknownEnumValue;
249+
SupplyStateEnum mSupplyStateBeforeFault = SupplyStateEnum::kUnknownEnumValue;
250+
158251
/* Callback related */
159252
EVSECallbackWrapper mCallbacks = { .handler = nullptr, .arg = 0 }; /* Wrapper to allow callbacks to be registered */
160253
Status NotifyApplicationCurrentLimitChange(int64_t maximumChargeCurrent);
161254
Status NotifyApplicationStateChange();
255+
Status GetEVSEEnergyMeterValue(ChargingDischargingType meterType, int64_t & aMeterValue);
256+
257+
/* Local State machine handling */
258+
Status CheckFaultOrDiagnostic();
259+
Status HandleStateMachineEvent(EVSEStateMachineEvent event);
260+
Status HandleEVPluggedInEvent();
261+
Status HandleEVNotDetectedEvent();
262+
Status HandleEVNoDemandEvent();
263+
Status HandleEVDemandEvent();
264+
Status HandleChargingEnabledEvent();
265+
Status HandleDischargingEnabledEvent();
266+
Status HandleDisabledEvent();
267+
Status HandleFaultRaised();
268+
Status HandleFaultCleared();
162269

163270
/**
164271
* @brief Helper function to work out the charge limit based on conditions and settings
165272
*/
166273
Status ComputeMaxChargeCurrentLimit();
167274

275+
/**
276+
* @brief This checks if the charging or discharging needs to be disabled
277+
*
278+
* @params pointer to SystemLayer
279+
* @params pointer to EnergyEvseDelegate
280+
*/
281+
static void EvseCheckTimerExpiry(System::Layer * systemLayer, void * delegate);
282+
168283
/* Attributes */
169284
StateEnum mState = StateEnum::kNotPluggedIn;
170285
SupplyStateEnum mSupplyState = SupplyStateEnum::kDisabled;
171286
FaultStateEnum mFaultState = FaultStateEnum::kNoError;
172287
DataModel::Nullable<uint32_t> mChargingEnabledUntil; // TODO Default to 0 to indicate disabled
173288
DataModel::Nullable<uint32_t> mDischargingEnabledUntil; // TODO Default to 0 to indicate disabled
174289
int64_t mCircuitCapacity = 0;
175-
int64_t mMinimumChargeCurrent = DEFAULT_MIN_CHARGE_CURRENT;
290+
int64_t mMinimumChargeCurrent = kDefaultMinChargeCurrent;
176291
int64_t mMaximumChargeCurrent = 0;
177292
int64_t mMaximumDischargeCurrent = 0;
178-
int64_t mUserMaximumChargeCurrent = DEFAULT_USER_MAXIMUM_CHARGE_CURRENT; // TODO update spec
179-
uint32_t mRandomizationDelayWindow = DEFAULT_RANDOMIZATION_DELAY_WINDOW;
293+
int64_t mUserMaximumChargeCurrent = kDefaultUserMaximumChargeCurrent; // TODO update spec
294+
uint32_t mRandomizationDelayWindow = kDefaultRandomizationDelayWindow;
180295
/* PREF attributes */
181296
uint8_t mNumberOfWeeklyTargets = 0;
182297
uint8_t mNumberOfDailyTargets = 1;
@@ -193,11 +308,11 @@ class EnergyEvseDelegate : public EnergyEvse::Delegate
193308
/* PNC attributes*/
194309
DataModel::Nullable<CharSpan> mVehicleID;
195310

196-
/* Session SESS attributes */
197-
DataModel::Nullable<uint32_t> mSessionID;
198-
DataModel::Nullable<uint32_t> mSessionDuration;
199-
DataModel::Nullable<int64_t> mSessionEnergyCharged;
200-
DataModel::Nullable<int64_t> mSessionEnergyDischarged;
311+
/* Session Object */
312+
EvseSession mSession = EvseSession(mEndpointId);
313+
314+
/* Helper variable to hold meter val since last EnergyTransferStarted event */
315+
int64_t mMeterValueAtEnergyTransferStart;
201316
};
202317

203318
} // namespace EnergyEvse

examples/energy-management-app/energy-management-common/include/EnergyEvseManager.h

+2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ class EnergyEvseManager : public Instance
4646
CHIP_ERROR Init();
4747
void Shutdown();
4848

49+
CHIP_ERROR LoadPersistentAttributes();
50+
4951
EnergyEvseDelegate * GetDelegate() { return mDelegate; };
5052

5153
private:

0 commit comments

Comments
 (0)