Smart Charging — Migration Guide
All differences in the Smart Charging section (K) between OCPP 2.0.1 (Edition 4) and OCPP 2.1 (Edition 2) from a CSMS implementation perspective.
Created by tzi.app — your guide to migrating from OCPP 2.0.1 to OCPP 2.1.
1. Summary of Changes
High-Level Overview
| Area | Change Type | Impact |
|---|---|---|
| Charging Profile Purposes | 2 new purposes | High — new profile types to support |
| Charging Profile Kind | 1 new kind (Dynamic) | Medium — new schedule update pattern |
| Operation Modes | 8 new modes (V2X) | High — fundamental behavior change for bidirectional charging |
| ChargingSchedulePeriodType | 13 new fields | High — V2X, per-phase, reactive power fields |
| ISO 15118-20 support | New use cases K18-K20 | High — new EV communication protocol |
| Priority Charging | New use cases K21-K22 | Medium — new message + profile purpose |
| EMS Topologies | New use cases K23-K27 | Low — CSMS behavior largely unchanged |
| Offline behavior | New fields | Medium — new offline validity logic |
| SoC-based limiting | New limitAtSoC field | Low — optional schedule feature |
| Randomized delays | New randomizedDelay | Low — optional load spreading |
2. New Use Cases
The following use cases are new in OCPP 2.1 and do not exist in 2.0.1:
| Use Case | Name | Description | CSMS Impact |
|---|---|---|---|
| K18 | ISO 15118-20 Scheduled Control Mode | EV selects from offered schedules using ISO 15118-20 | High |
| K19 | ISO 15118-20 Dynamic Control Mode | CS dynamically controls EV charging rate | High |
| K20 | ISO 15118-20 Adjusting Schedule on Energy Needs Change | EV reports changed departure time or energy needs mid-session | Medium |
| K21 | Activate Priority Charging | Activate priority charging for a transaction | Medium |
| K22 | Deactivate Priority Charging | Deactivate priority charging for a transaction | Medium |
| K23 | Smart Charging with EMS Connected to Charging Stations | EMS directly connected to stations | Low |
| K24 | Smart Charging with EMS Connected to Local Controller | EMS connected via Local Controller | Low |
| K25 | Smart Charging with EMS Acting as Local Controller | Combined EMS/Local Controller | Low |
| K26 | Smart Charging with Hybrid Local & Cloud EMS | Hybrid EMS topology | Low |
| K27 | Smart Charging with EMS and LocalGeneration | Local generation (e.g., solar) integration | Medium |
3. New Charging Profile Purposes
Two new chargingProfilePurpose values are added in 2.1:
3.1 PriorityCharging (New)
| Property | Value |
|---|---|
| evseId | > 0 only |
| Persistence | Must persist across reboots |
| Overrules | TxProfile and TxDefaultProfile |
| Constraints | operationMode must be ChargingOnly; no duration allowed in schedule |
| Activation | Via UsePriorityChargingRequest (not automatic upon install) |
The CSMS pre-installs a PriorityCharging profile and then activates/deactivates it per transaction using the new UsePriorityChargingRequest message.
3.2 LocalGeneration (New)
| Property | Value |
|---|---|
| evseId | 0 or > 0 |
| Persistence | NOT required to persist |
| Effect | Capacity is added on top of the composite schedule (not used as a minimum) |
| Set by | External systems (EMS), NOT by CSMS |
Key difference: LocalGeneration capacity is additive, not limiting. This is fundamentally different from all other profile purposes.
Updated Composite Schedule Calculation
2.0.1
min(CSMaxProfile, CSExtConstraints, TxDefault/TxProfile)2.1
min(CSMaxProfile, CSExtConstraints, TxDefault/TxProfile/PriorityCharging) + LocalGeneration4. New Charging Profile Kind: Dynamic
| Property | 2.0.1 | 2.1 |
|---|---|---|
| Available Kinds | Absolute, Recurring, Relative | Absolute, Recurring, Relative, Dynamic |
Dynamic Kind
- Contains a single period that is updated dynamically by the CSMS or external actor.
- No startSchedule required.
- Associated fields: dynUpdateInterval (seconds between update requests) and dynUpdateTime (last update time).
- Used primarily in ISO 15118-20 Dynamic Control Mode (K19) but can also be used for external setpoint control.
5. New Operation Modes
2.0.1: No operation mode concept. All charging is implicitly unidirectional charge-only.
2.1: Each ChargingSchedulePeriodType can specify an operationMode:
| Mode | Direction | Description |
|---|---|---|
ChargingOnly | Unidirectional | Default. Only limit field used. Equivalent to 2.0.1 behavior. |
ExternalSetpoint | Unidirectional | setpoint determined by external actor (EMS) |
ExternalLimits | Unidirectional | limit determined by external actor |
CentralSetpoint | Bidirectional | setpoint set by CSMS (can be negative for discharge) |
CentralFrequency | Bidirectional | Frequency-watt curve based control |
LocalFrequency | Bidirectional | Local frequency response |
LocalLoadBalancing | Bidirectional | Local load balancing |
Idle | Bidirectional | EVSE sleep mode |
CSMS Impact: If your CSMS only does unidirectional charging, you can ignore most operation modes and stick with ChargingOnly (default). For V2X / bidirectional support, you must handle CentralSetpoint at minimum.
6. ChargingProfileType Changes
New Fields
| Field | Type | Description |
|---|---|---|
maxOfflineDuration | integer | Seconds the profile remains valid while CS is offline. 0 = immediately invalid. Absent = no timeout. |
invalidAfterOfflineDuration | boolean | If true, profile becomes permanently invalid after offline timeout. Default: false (reactivates on reconnect). |
dynUpdateInterval | integer | For Dynamic kind: seconds between update requests. |
dynUpdateTime | dateTime | For Dynamic kind: last update time. |
Changed Behaviors
| Aspect | 2.0.1 | 2.1 |
|---|---|---|
| Profile id value range | Positive integers | Can be negative |
| Offline behavior | Profile always valid while offline (K06/K07) | Configurable via maxOfflineDuration + invalidAfterOfflineDuration |
| Profile uniqueness (non-TxProfile) | stackLevel + purpose + evseId | Same, but must also respect MaxExternalConstraintsId for id values |
7. ChargingScheduleType Changes
New Fields
| Field | Type | Description |
|---|---|---|
useLocalTime | boolean | If true, treat startSchedule as local time (ignoring timezone offset) |
randomizedDelay | integer (>=0) | Max random delay in seconds for period starts. Only for TxProfile/TxDefaultProfile. First period (startPeriod=0) is NOT delayed. |
limitAtSoC | LimitAtSoCType | Cap limit/setpoint when EV SoC exceeds threshold |
absolutePriceSchedule | AbsolutePriceScheduleType | ISO 15118-20 price schedule (replaces/supplements salesTariff) |
priceLevelSchedule | PriceLevelScheduleType | ISO 15118-20 price levels |
New Type: LimitAtSoCType
{
"soc": 80, // 0-100, SoC threshold percentage
"limit": 3000 // Charging rate limit when SoC >= threshold
}Price Schedule Changes
| Aspect | 2.0.1 | 2.1 |
|---|---|---|
| Price information | salesTariff only (ISO 15118-2) | salesTariff (ISO 15118-2) OR absolutePriceSchedule OR priceLevelSchedule (ISO 15118-20) |
8. ChargingSchedulePeriodType Changes
Largest data model change in Smart Charging. The 2.0.1 period had 4 fields; 2.1 has up to 17.
New Fields
| Field | Type | Description |
|---|---|---|
limit_L2 | number | Per-phase limit for L2 (AC only) |
limit_L3 | number | Per-phase limit for L3 (AC only) |
dischargeLimit | number (<=0) | Max discharge rate (negative value, V2X) |
dischargeLimit_L2 | number (<=0) | Per-phase discharge limit for L2 |
dischargeLimit_L3 | number (<=0) | Per-phase discharge limit for L3 |
setpoint | number | Target charge/discharge rate (negative = discharge) |
setpoint_L2 | number | Per-phase setpoint for L2 |
setpoint_L3 | number | Per-phase setpoint for L3 |
setpointReactive | number | Reactive power setpoint (+inductive, -capacitive) |
setpointReactive_L2 | number | Per-phase reactive setpoint for L2 |
setpointReactive_L3 | number | Per-phase reactive setpoint for L3 |
operationMode | enum | Operation mode for this period (default: ChargingOnly) |
evseSleep | boolean | EVSE turns off power electronics. Only valid with operationMode = Idle |
preconditioningRequest | boolean | Request EV to keep BMS preconditioned |
Changed Fields
| Field | 2.0.1 | 2.1 |
|---|---|---|
limit | Always required | Conditional — required for ChargingOnly mode, optional for other modes |
numberPhases | Optional, default 3 | Optional, default 3 for AC. Omit for DC. Range is now explicitly 0-3 (0 = DC). |
Per-Phase Limit Rules (New in 2.1)
- limit_L2/limit_L3 can only be used in TxProfile.
- Only provide them after receiving NotifyEVChargingNeedsRequest with maxChargePower_L2/maxChargePower_L3 in V2XChargingParametersType.
9. ChargingLimitType Changes
New Field
| Field | Type | Description |
|---|---|---|
isLocalGeneration | boolean | true if reporting local generation capacity (extra capacity, not a limitation) |
2.0.1
ChargingLimitType only had chargingLimitSource and isGridCritical.
2.1
Adds isLocalGeneration to distinguish between external constraints (limitations) and local generation (additional capacity).
10. ChargingNeedsType Changes (ISO 15118)
New Fields
| Field | Type | Description |
|---|---|---|
v2xChargingParameters | V2XChargingParametersType | ISO 15118-20 V2X parameters (replaces ac/dcChargingParameters for 15118-20) |
derChargingParameters | DERChargingParametersType | ISO 15118-20 DER (Distributed Energy Resource) parameters |
evEnergyOffer | EVEnergyOfferType | EV's energy offer for V2X (e.g., willingness to discharge) |
availableEnergyTransfer | enum[] | Other available energy transfer modes beyond the requested one |
controlMode | enum | ScheduledControl or DynamicControl |
mobilityNeedsMode | enum | EVCC or EVCC_SECC |
New requestedEnergyTransfer Values
| 2.0.1 Values | New in 2.1 |
|---|---|
| DC, AC_single_phase, AC_two_phase, AC_three_phase | AC_BPT, AC_BPT_DER, AC_DER, DC_BPT, DC_ACDP, DC_ACDP_BPT, WPT |
BPT = Bidirectional Power Transfer, DER = Distributed Energy Resource, ACDP = AC with DC Power, WPT = Wireless Power Transfer
V2XChargingParametersType (New)
Key fields for V2X/bidirectional charging:
| Field | Description |
|---|---|
maxChargePower / _L2 / _L3 | Max charge power per phase (W) |
minChargePower / _L2 / _L3 | Min charge power per phase (W) |
maxDischargePower / _L2 / _L3 | Max discharge power per phase (W) |
minDischargePower / _L2 / _L3 | Min discharge power per phase (W) |
maxChargeCurrent / maxDischargeCurrent | DC current limits (A) |
minChargeCurrent / minDischargeCurrent | DC current minimums (A) |
minVoltage / maxVoltage | Voltage range (V) |
evTargetEnergyRequest | Target energy (Wh) |
evMinEnergyRequest / evMaxEnergyRequest | Energy range (Wh) |
evMinV2XEnergyRequest / evMaxV2XEnergyRequest | V2X cycling energy (Wh) |
targetSoC | Target departure SoC (0-100) |
NotifyEVChargingNeedsRequest Changes
| Field | 2.0.1 | 2.1 |
|---|---|---|
timestamp | Not present | New — when the needs were received (useful for offline scenarios) |
11. NotifyEVChargingNeedsResponse Changes
New Status Value
| Status | 2.0.1 | 2.1 |
|---|---|---|
Accepted | Yes | Yes |
Rejected | Yes | Yes |
Processing | Yes | Yes |
NoChargingProfile New | No | Yes |
NoChargingProfile is used specifically in K18 (ISO 15118-20 Scheduled) and K19 (ISO 15118-20 Dynamic) when the CSMS doesn't want to provide a profile but doesn't reject the needs either.
12. NotifyEVChargingScheduleRequest Changes
New Fields
| Field | Type | Description |
|---|---|---|
selectedChargingScheduleId | integer (>=0) | ID of the schedule the EV selected from the CSMS-provided ChargingProfile |
powerToleranceAcceptance | boolean | true if EV accepts the power tolerance |
Changed Field Behavior
| Field | 2.0.1 | 2.1 |
|---|---|---|
| chargingSchedule periods | limit only | Can also include limit_L2, limit_L3 |
| chargingRateUnit | "W" or "A" | Must be "W" for this message |
13. SetChargingProfileResponse Changes
New Rejection Reason Codes
| reasonCode | 2.0.1 | 2.1 | Description |
|---|---|---|---|
TxNotFound | Yes | Yes | No active transaction on EVSE |
UnknownEVSE | Yes | Yes | evseId does not exist |
UnsupportedRateUnit | Yes | Yes | chargingRateUnit not supported |
DuplicateProfile | Yes | Yes | stackLevel+purpose conflict |
InvalidSchedule | Yes | Yes | Expanded: now also covers useLocalTime, randomizedDelay, limitAtSoC, duration on PriorityCharging |
InvalidProfile New | No | Yes | dynUpdateInterval/dynUpdateTime on non-Dynamic profile |
InvalidProfileId New | No | Yes | Profile ID <= MaxExternalConstraintsId when config var is set |
InvalidOperationMode New | No | Yes | Operation mode not valid for profile purpose or not supported |
UnsupportedPurpose New | No | Yes | PriorityCharging or LocalGeneration not in SupportedAdditionalPurposes |
PhaseConflict New | No | Yes | Conflicting phaseToUse between profiles |
NoPhaseForDC New | No | Yes | numberPhases/phaseToUse on DC EVSE without DCInputPhaseControl |
RateLimitExceeded New | No | Yes | Too many frequent updates threatening persistent memory |
RateLimitExceeded Handling (New)
When the CS responds with RateLimitExceeded, the CSMS must read the delay from statusInfo.additionalInfo and wait before retrying.
14. CompositeScheduleType Changes
Behavioral Changes
| Aspect | 2.0.1 | 2.1 |
|---|---|---|
| Reported values | Minimum limit across all purposes | Lowest limit and setpoint when charging; highest dischargeLimit and setpoint when discharging |
| LocalGeneration | Not applicable | LocalGeneration capacity added on top |
| V2X fields | Not present | Periods may include dischargeLimit, setpoint, and per-phase variants |
15. ClearChargingProfile Changes
Additional Restriction
| Aspect | 2.0.1 | 2.1 |
|---|---|---|
| Cannot clear | ChargingStationExternalConstraints | ChargingStationExternalConstraints AND LocalGeneration |
16. New Message: UsePriorityChargingRequest / Response
This is an entirely new message pair in 2.1 (used by K21/K22).
UsePriorityChargingRequest (CSMS → CS)
{
"transactionId": "string (max 36)", // REQUIRED
"activate": true // REQUIRED - true=enable, false=disable
}UsePriorityChargingResponse (CS → CSMS)
{
"status": "Accepted" | "Rejected" | "NoProfile",
"statusInfo": { ... }
}| Status | Meaning |
|---|---|
Accepted | Priority charging activated/deactivated |
Rejected | Request denied |
NoProfile | No PriorityCharging profile is installed on the CS |
Workflow
- 1 Pre-install a PriorityCharging profile via SetChargingProfileRequest.
- 2 Send UsePriorityChargingRequest with activate=true to activate for a specific transaction.
- 3 The PriorityCharging profile overrules TxProfile/TxDefaultProfile, providing max possible power.
- 4 Send with activate=false to deactivate.
17. Flow-by-Flow Changes (K01-K17)
K01 SetChargingProfile
- New purposes: can now set PriorityCharging and LocalGeneration (but NOT ChargingStationExternalConstraints)
- New kind: Dynamic kind supported
- New schedule fields: useLocalTime, randomizedDelay, limitAtSoC, absolutePriceSchedule, priceLevelSchedule
- New period fields: all V2X/per-phase/reactive fields, operationMode, evseSleep, preconditioningRequest
- Profile ID range: can now be negative
- MaxExternalConstraintsId: when configured, CSMS must choose profile id values higher than this value
- limit field: no longer always required in periods; conditional on operationMode
- New rejection codes: InvalidProfile, InvalidProfileId, InvalidOperationMode, UnsupportedPurpose, PhaseConflict, NoPhaseForDC, RateLimitExceeded
- Offline fields: new maxOfflineDuration, invalidAfterOfflineDuration on profiles
K02 Central Smart Charging
- No structural changes. Same flow. New profile fields available but existing behavior unchanged.
- New FR: K02.FR.07 explicitly added — MUST NOT set purpose to ChargingStationExternalConstraints
K03 Local Smart Charging
- No structural changes. Same CSMS role.
K04 Internal Load Balancing
- LocalGeneration additive: K04.FR.05 now states combined energy flow SHALL NOT exceed ChargingStationMaxProfile + LocalGeneration
K05 Remote Start Transaction with Charging Profile
- No structural changes. Same flow. New profile fields available.
K06 Offline Behavior During Transaction
- New offline control: CSMS can now use maxOfflineDuration and invalidAfterOfflineDuration for fine-grained offline behavior. In 2.0.1, profiles were simply always valid while offline.
K07 Offline Behavior at Start of Transaction
- Same as K06: new offline control fields apply to TxDefaultProfile as well.
K08 Get Composite Schedule
- V2X in response: composite schedule periods may now include dischargeLimit, setpoint, and per-phase variants.
- Calculation change: now reports lowest limit/setpoint when charging, highest dischargeLimit/setpoint when discharging. LocalGeneration added on top.
K09 Get Charging Profiles
- No structural changes. Reported profiles may now include new purposes (PriorityCharging, LocalGeneration) and new fields.
K10 Clear Charging Profile
- Additional restriction: CSMS SHALL NOT set chargingProfilePurpose to LocalGeneration in addition to the existing ChargingStationExternalConstraints restriction.
K11 Set/Update External Charging Limit With Ongoing Transaction
- isLocalGeneration field: new field in ChargingLimitType. When true, indicates extra capacity, not a limitation.
- ExternalConstraintsProfileDisallowed: new config — if true, station ignores external limits; CSMS must use operationMode = ExternalLimits instead.
- Profile ID conventions: when MaxExternalConstraintsId is set, station uses IDs below that value; when not set, negative IDs are used for external constraints profiles.
K12 Set/Update External Charging Limit Without Ongoing Transaction
- Same changes as K11: isLocalGeneration, ExternalConstraintsProfileDisallowed, profile ID conventions.
K13 Reset/Release External Charging Limit
- No structural changes. Same flow and messages.
K14 External Charging Limit with Local Controller
- K14.FR.06: new requirement — Local Controller SHALL NOT set purpose to ChargingStationExternalConstraints (uses ChargingStationMaxProfile instead).
K15 ISO 15118-2 Charging with Load Leveling
- timestamp field: new optional field on NotifyEVChargingNeedsRequest.
- K15.FR.18: new recommendation — use only one chargingSchedule per SetChargingProfileRequest to avoid ambiguity.
- Period limit: now also constrained by SmartChargingCtrlr.PeriodsPerSchedule in addition to maxScheduleTuples.
K16 Renegotiation Initiated by CSMS
- K16.FR.09: clarified — station SHOULD NOT send NotifyEVChargingNeedsRequest during CSMS-initiated renegotiation.
- K16.FR.12: new — if station sends NotifyEVChargingNeedsRequest anyway, CSMS SHALL send a SetChargingProfileRequest.
K17 Renegotiation Initiated by EV
- ISO 15118-20 support: K17.FR.06 expects V2XChargingParametersType for ISO 15118-20 sessions.
- Dynamic control: K17.FR.19 — for DynamicControl mode, send 1 chargingSchedule with chargingSchedulePeriods and optional price info.
- controlMode field: new field in chargingNeeds affects profile structure.
18. New Configuration Variables
| Variable | Description | Impact |
|---|---|---|
ExternalConstraintsProfileDisallowed | When true, CS ignores external charging limits set as ChargingStationExternalConstraints profiles | CSMS must use operationMode = ExternalLimits instead (K29) |
MaxExternalConstraintsId | Maximum profile ID value for external constraints profiles | CSMS must choose profile IDs higher than this value |
SmartChargingCtrlr.PeriodsPerSchedule | Max number of schedule periods per schedule | Limits chargingSchedulePeriod entries CSMS can send |
SupportedAdditionalPurposes | Which additional purposes the CS supports (e.g., PriorityCharging, LocalGeneration) | CSMS must check before sending profiles with these purposes |
Existing Variables (Unchanged)
These variables exist in both versions with the same behavior:
ChargingScheduleChargingRateUnitEnabled (SmartChargingCtrlr)ACPhaseSwitchingSupportedLimitChangeSignificanceExternalControlSignalsEnabledEnableNotifyChargingLimitWithSchedulesPhases3to119. StatusInfoType Changes
| Field | 2.0.1 | 2.1 |
|---|---|---|
additionalInfo max length | 512 characters | 1024 characters |
20. Profile Persistence Requirements
2.1 adds explicit persistence requirements per purpose (not specified in 2.0.1):
| Purpose | Must Persist Across Reboots |
|---|---|
ChargingStationMaxProfile | Yes |
TxDefaultProfile | Yes |
PriorityCharging New | Yes |
TxProfile | No (but MAY) |
LocalGeneration New | No (but MAY) |
ChargingStationExternalConstraints | No (but MAY) |
21. Migration Checklist
Must Do Breaking / Required Changes
- Support new chargingProfilePurpose values: PriorityCharging, LocalGeneration
- Support new chargingProfileKind: Dynamic
- Handle new SetChargingProfileResponse rejection codes: InvalidProfile, InvalidProfileId, InvalidOperationMode, UnsupportedPurpose, PhaseConflict, NoPhaseForDC, RateLimitExceeded
- Handle RateLimitExceeded with retry delay from statusInfo.additionalInfo
- Support maxOfflineDuration and invalidAfterOfflineDuration in profile management
- Implement UsePriorityChargingRequest/Response message pair (K21/K22)
- Handle NoChargingProfile status in NotifyEVChargingNeedsResponse
- Respect MaxExternalConstraintsId when assigning profile IDs
- Support negative profile id values
- Update ClearChargingProfile to also exclude LocalGeneration purpose
- Handle isLocalGeneration in NotifyChargingLimitRequest (additive capacity, not a limit)
- Update additionalInfo max length from 512 to 1024 characters
- Handle selectedChargingScheduleId and powerToleranceAcceptance in NotifyEVChargingScheduleRequest
Should Do ISO 15118-20 Support
- Support V2XChargingParametersType in NotifyEVChargingNeedsRequest
- Support controlMode field (ScheduledControl / DynamicControl)
- Support ISO 15118-20 price schedules (absolutePriceSchedule, priceLevelSchedule)
- Implement K18 (Scheduled Control Mode) — up to 3 schedules with price info
- Implement K19 (Dynamic Control Mode) — exactly 1 schedule, CS controls rate
- Implement K20 (Energy Needs Change) — handle updated departure/energy mid-session
- Support new requestedEnergyTransfer values: AC_BPT, DC_BPT, DC_ACDP, WPT, etc.
- Handle timestamp field on NotifyEVChargingNeedsRequest
Should Do V2X / Bidirectional Support
- Support operationMode in ChargingSchedulePeriodType
- Support discharge fields: dischargeLimit, dischargeLimit_L2, dischargeLimit_L3
- Support setpoint fields: setpoint, setpoint_L2, setpoint_L3
- Support reactive power fields: setpointReactive, setpointReactive_L2, setpointReactive_L3
- Support evseSleep and preconditioningRequest in periods
- Handle evEnergyOffer in charging needs (EV willing to discharge)
Optional Nice to Have
- Support useLocalTime in charging schedules
- Support randomizedDelay for load spreading
- Support limitAtSoC for SoC-based charging rate caps
- Support per-phase limits: limit_L2, limit_L3 in TxProfile
- Implement K23-K27 EMS topology awareness (mostly informational, same CSMS behavior as K11/K12/K14)