Skip to content

Commit

Permalink
EVSE add Session and Event support, test event trigger support (#31200)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
3 people committed Jan 17, 2024
1 parent c4f7024 commit 4abbe28
Show file tree
Hide file tree
Showing 22 changed files with 2,788 additions and 226 deletions.
2 changes: 2 additions & 0 deletions .github/.wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -519,8 +519,10 @@ EthyleneOxideConcentrationMeasurement
EvalCode
EvalCodeWithName
EvalFrameDefault
EV
EVB
evk
EVSE
exceptfds
ExchangeContext
exe
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,41 @@ using namespace chip::app::Clusters::EnergyEvse;
* This is not specific to the EnergyEVSE cluster, but includes DeviceEnergyManagement
* and potential future clusters.
*/
enum EVSECallbackType
enum class EVSECallbackType : uint8_t
{
/*
* The State has changed (e.g. from Disabled to Charging, or vice-versa)
*/
StateChanged,
/*
* ChargeCurrent has changed
* ChargeCurrent has changed (e.g. maxChargingCurrent so requires an
update to advertise a different charging current to the EV)
*/
ChargeCurrentChanged,
/*
* Charging Preferences have changed
* The daily charging target time, SoC / Added Energy schedules have changed
* and may require the local optimiser to re-run.
*/
ChargingPreferencesChanged,
/*
* DeviceEnergyManagement has changed
* Energy Meter Reading requested from the hardware, e.g. so that the session
* information can be updated.
*/
EnergyMeterReadingRequested,
/*
* The associated DeviceEnergyManagement cluster has changed. This may mean
* that the start time, or power profile or power levels have been adjusted
*/
DeviceEnergyManagementChanged,
};

enum class ChargingDischargingType : uint8_t
{
kCharging,
kDischarging
};

struct EVSECbInfo
{
EVSECallbackType type;
Expand All @@ -68,6 +83,13 @@ struct EVSECbInfo
{
int64_t maximumChargeCurrent;
} ChargingCurrent;

/* for type = EnergyMeterReadingRequested */
struct
{
ChargingDischargingType meterType;
int64_t * energyMeterValuePtr;
} EnergyMeterReadingRequest;
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,50 @@ namespace EnergyEvse {
class EVSEManufacturer
{
public:
EVSEManufacturer(EnergyEvseManager * aInstance) { mInstance = aInstance; }
EnergyEvseManager * GetInstance() { return mInstance; }
EnergyEvseDelegate * GetDelegate()
{
if (mInstance)
{
return mInstance->GetDelegate();
}
return nullptr;
}

/**
* @brief Called at start up to apply hardware settings
*/
CHIP_ERROR Init(EnergyEvseManager * aInstance);
CHIP_ERROR Init();

/**
* @brief Called at shutdown
*/
CHIP_ERROR Shutdown(EnergyEvseManager * aInstance);
CHIP_ERROR Shutdown();

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

private:
EnergyEvseManager * mInstance;

int64_t mLastChargingEnergyMeter = 0;
int64_t mLastDischargingEnergyMeter = 0;
};

/** @brief Helper function to return the singleton EVSEManufacturer instance
*
* This is needed by the EVSEManufacturer class to support TestEventTriggers
* which are called outside of any class context. This allows the EVSEManufacturer
* class to return the relevant Delegate instance in which to invoke the test
* events on.
*
* This function is typically found in main.cpp or wherever the singleton is created.
*/
EVSEManufacturer * GetEvseManufacturer();

} // namespace EnergyEvse
} // namespace Clusters
} // namespace app
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,68 @@ namespace app {
namespace Clusters {
namespace EnergyEvse {

/* Local state machine Events to allow simpler handling of state transitions */
enum EVSEStateMachineEvent
{
EVPluggedInEvent, /* EV has been plugged in */
EVNotDetectedEvent, /* EV has been unplugged or detected as not connected */
EVNoDemandEvent, /* EV has stopped asking for demand */
EVDemandEvent, /* EV has asked for demand*/
ChargingEnabledEvent, /* Charging has been enabled */
DischargingEnabledEvent, /* Discharging has been enabled */
DisabledEvent, /* EVSE has been disabled */
FaultRaised, /* Fault has been raised */
FaultCleared, /* Fault has been cleared */
};

/**
* Helper class to handle all of the session related info
*/
class EvseSession
{
public:
EvseSession(EndpointId aEndpoint) { mEndpointId = aEndpoint; }
/**
* @brief This function records the start time and provided energy meter values as part of the new session.
*
* @param chargingMeterValue - The current value of the energy meter (charging) in mWh
* @param dischargingMeterValue - The current value of the energy meter (discharging) in mWh
*/
void StartSession(int64_t chargingMeterValue, int64_t dischargingMeterValue);

/**
* @brief This function updates the session Duration to allow read attributes to return latest values
*/
void RecalculateSessionDuration();

/**
* @brief This function updates the EnergyCharged meter value
*
* @param chargingMeterValue - The value of the energy meter (charging) in mWh
*/
void UpdateEnergyCharged(int64_t chargingMeterValue);

/**
* @brief This function updates the EnergyDischarged meter value
*
* @param dischargingMeterValue - The value of the energy meter (discharging) in mWh
*/
void UpdateEnergyDischarged(int64_t dischargingMeterValue);

/* Public members - represent attributes in the cluster */
DataModel::Nullable<uint32_t> mSessionID;
DataModel::Nullable<uint32_t> mSessionDuration;
DataModel::Nullable<int64_t> mSessionEnergyCharged;
DataModel::Nullable<int64_t> mSessionEnergyDischarged;

private:
EndpointId mEndpointId = 0;

uint32_t mStartTime = 0; // Epoch_s - 0 means it hasn't started yet
int64_t mSessionEnergyChargedAtStart = 0; // in mWh - 0 means it hasn't been set yet
int64_t mSessionEnergyDischargedAtStart = 0; // in mWh - 0 means it hasn't been set yet
};

/**
* The application delegate.
*/
Expand Down Expand Up @@ -74,15 +136,41 @@ class EnergyEvseDelegate : public EnergyEvse::Delegate
*/
Status HwRegisterEvseCallbackHandler(EVSECallbackFunc handler, intptr_t arg);

/**
* @brief Decides if a timer is needed based on EVSE state and sets a callback if needed
*
* In order to ensure the EVSE restarts charging (if enabled) after power loss
* this should be called after the EVSE is initialised
* (e.g. HwSetMaxHardwareCurrentLimit and HwSetCircuitCapacity have been called)
* and the persisted attributes have been loaded, and time has been synchronised.
*
* If time isn't sync'd yet it will call itself back periodically (if required)
* until time is sync'd.
*
* It is also called when a EnableCharging or EnableDischarging command
* is recv'd to schedule when the EVSE should be automatically disabled based
* on ChargingEnabledUntil / DischargingEnabledUntil expiring.
*/
Status ScheduleCheckOnEnabledTimeout();

// -----------------------------------------------------------------
// Internal API to allow an EVSE to change its internal state etc
Status HwSetMaxHardwareCurrentLimit(int64_t currentmA);
int64_t HwGetMaxHardwareCurrentLimit() { return mMaxHardwareCurrentLimit; }
Status HwSetCircuitCapacity(int64_t currentmA);
Status HwSetCableAssemblyLimit(int64_t currentmA);
int64_t HwGetCableAssemblyLimit() { return mCableAssemblyCurrentLimit; }
Status HwSetState(StateEnum state);
StateEnum HwGetState() { return mHwState; };
Status HwSetFault(FaultStateEnum fault);
Status HwSetRFID(ByteSpan uid);
Status HwSetVehicleID(const CharSpan & vehID);
Status HwDiagnosticsComplete();
Status SendEVConnectedEvent();
Status SendEVNotDetectedEvent();
Status SendEnergyTransferStartedEvent();
Status SendEnergyTransferStoppedEvent(EnergyTransferStoppedReasonEnum reason);
Status SendFaultEvent(FaultStateEnum newFaultState);

// ------------------------------------------------------------------
// Get attribute methods
Expand All @@ -96,10 +184,10 @@ class EnergyEvseDelegate : public EnergyEvse::Delegate
CHIP_ERROR SetFaultState(FaultStateEnum);

DataModel::Nullable<uint32_t> GetChargingEnabledUntil() override;
CHIP_ERROR SetChargingEnabledUntil(uint32_t);
CHIP_ERROR SetChargingEnabledUntil(DataModel::Nullable<uint32_t>);

DataModel::Nullable<uint32_t> GetDischargingEnabledUntil() override;
CHIP_ERROR SetDischargingEnabledUntil(uint32_t);
CHIP_ERROR SetDischargingEnabledUntil(DataModel::Nullable<uint32_t>);

int64_t GetCircuitCapacity() override;
CHIP_ERROR SetCircuitCapacity(int64_t);
Expand Down Expand Up @@ -128,7 +216,7 @@ class EnergyEvseDelegate : public EnergyEvse::Delegate
DataModel::Nullable<Percent> GetNextChargeTargetSoC() override;

DataModel::Nullable<uint16_t> GetApproximateEVEfficiency() override;
CHIP_ERROR SetApproximateEVEfficiency(uint16_t) override;
CHIP_ERROR SetApproximateEVEfficiency(DataModel::Nullable<uint16_t>) override;

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

private:
/* Constants */
static constexpr int DEFAULT_MIN_CHARGE_CURRENT = 6000; /* 6A */
static constexpr int DEFAULT_USER_MAXIMUM_CHARGE_CURRENT = kMaximumChargeCurrent; /* 80A */
static constexpr int DEFAULT_RANDOMIZATION_DELAY_WINDOW = 600; /* 600s */
static constexpr int kMaxVehicleIDBufSize = 32;
static constexpr int kDefaultMinChargeCurrent = 6000; /* 6A */
static constexpr int kDefaultUserMaximumChargeCurrent = kMaximumChargeCurrent; /* 80A */
static constexpr int kDefaultRandomizationDelayWindow = 600; /* 600s */
static constexpr int kMaxVehicleIDBufSize = 32;
static constexpr int kPeriodicCheckIntervalRealTimeClockNotSynced = 30;

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

/* Variables to hold State and SupplyState in case a fault is raised */
StateEnum mStateBeforeFault = StateEnum::kUnknownEnumValue;
SupplyStateEnum mSupplyStateBeforeFault = SupplyStateEnum::kUnknownEnumValue;

/* Callback related */
EVSECallbackWrapper mCallbacks = { .handler = nullptr, .arg = 0 }; /* Wrapper to allow callbacks to be registered */
Status NotifyApplicationCurrentLimitChange(int64_t maximumChargeCurrent);
Status NotifyApplicationStateChange();
Status GetEVSEEnergyMeterValue(ChargingDischargingType meterType, int64_t & aMeterValue);

/* Local State machine handling */
Status CheckFaultOrDiagnostic();
Status HandleStateMachineEvent(EVSEStateMachineEvent event);
Status HandleEVPluggedInEvent();
Status HandleEVNotDetectedEvent();
Status HandleEVNoDemandEvent();
Status HandleEVDemandEvent();
Status HandleChargingEnabledEvent();
Status HandleDischargingEnabledEvent();
Status HandleDisabledEvent();
Status HandleFaultRaised();
Status HandleFaultCleared();

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

/**
* @brief This checks if the charging or discharging needs to be disabled
*
* @params pointer to SystemLayer
* @params pointer to EnergyEvseDelegate
*/
static void EvseCheckTimerExpiry(System::Layer * systemLayer, void * delegate);

/* Attributes */
StateEnum mState = StateEnum::kNotPluggedIn;
SupplyStateEnum mSupplyState = SupplyStateEnum::kDisabled;
FaultStateEnum mFaultState = FaultStateEnum::kNoError;
DataModel::Nullable<uint32_t> mChargingEnabledUntil; // TODO Default to 0 to indicate disabled
DataModel::Nullable<uint32_t> mDischargingEnabledUntil; // TODO Default to 0 to indicate disabled
int64_t mCircuitCapacity = 0;
int64_t mMinimumChargeCurrent = DEFAULT_MIN_CHARGE_CURRENT;
int64_t mMinimumChargeCurrent = kDefaultMinChargeCurrent;
int64_t mMaximumChargeCurrent = 0;
int64_t mMaximumDischargeCurrent = 0;
int64_t mUserMaximumChargeCurrent = DEFAULT_USER_MAXIMUM_CHARGE_CURRENT; // TODO update spec
uint32_t mRandomizationDelayWindow = DEFAULT_RANDOMIZATION_DELAY_WINDOW;
int64_t mUserMaximumChargeCurrent = kDefaultUserMaximumChargeCurrent; // TODO update spec
uint32_t mRandomizationDelayWindow = kDefaultRandomizationDelayWindow;
/* PREF attributes */
uint8_t mNumberOfWeeklyTargets = 0;
uint8_t mNumberOfDailyTargets = 1;
Expand All @@ -193,11 +308,11 @@ class EnergyEvseDelegate : public EnergyEvse::Delegate
/* PNC attributes*/
DataModel::Nullable<CharSpan> mVehicleID;

/* Session SESS attributes */
DataModel::Nullable<uint32_t> mSessionID;
DataModel::Nullable<uint32_t> mSessionDuration;
DataModel::Nullable<int64_t> mSessionEnergyCharged;
DataModel::Nullable<int64_t> mSessionEnergyDischarged;
/* Session Object */
EvseSession mSession = EvseSession(mEndpointId);

/* Helper variable to hold meter val since last EnergyTransferStarted event */
int64_t mMeterValueAtEnergyTransferStart;
};

} // namespace EnergyEvse
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ class EnergyEvseManager : public Instance
CHIP_ERROR Init();
void Shutdown();

CHIP_ERROR LoadPersistentAttributes();

EnergyEvseDelegate * GetDelegate() { return mDelegate; };

private:
Expand Down
Loading

0 comments on commit 4abbe28

Please sign in to comment.