Smart charging is functional block K. The core idea is the same as in 1.6: the CSMS sends charging profiles, each a time-based schedule of power or current limits, and the station combines them into an effective limit. 2.0.1 renames some purposes, adds a way for local systems to impose limits that the CSMS can see, and connects to ISO 15118 so the EV can say what it needs. If smart charging is new to you, start with smart charging and load management for the why.
ChargingProfileType
{
"id": 101,
"stackLevel": 0,
"chargingProfilePurpose": "TxDefaultProfile",
"chargingProfileKind": "Recurring",
"recurrencyKind": "Daily",
"chargingSchedule": [
{
"id": 1,
"startSchedule": "2026-10-26T00:00:00.000Z",
"duration": 86400,
"chargingRateUnit": "A",
"chargingSchedulePeriod": [
{ "startPeriod": 0, "limit": 32.0, "numberPhases": 3 },
{ "startPeriod": 61200, "limit": 16.0, "numberPhases": 3 },
{ "startPeriod": 75600, "limit": 32.0, "numberPhases": 3 }
]
}
]
}This profile limits every new transaction to 32 A, dropping to 16 A between 17:00 and 21:00 UTC. Key fields:
chargingProfileKind:Absolute(starts atstartSchedule),Recurring(repeatsDailyorWeeklyfromstartSchedule) orRelative(starts when the transaction starts).chargingScheduleis an array in 2.0.1 (one to three schedules). More than one is only used with ISO 15118, where they become alternative schedules offered to the EV. For ordinary use, send one.- Each schedule has its own
id, achargingRateUnitofWorA, optionalminChargingRate, andchargingSchedulePeriodentries withstartPeriod(seconds from schedule start),limit, and optionalnumberPhasesandphaseToUse. validFrom/validTobound the profile;transactionIdbinds aTxProfileto one transaction.
Purposes and how they combine
| chargingProfilePurpose | Set by | Scope |
|---|---|---|
ChargingStationMaxProfile | CSMS | Overall limit for the whole station; only on evseId 0. |
TxDefaultProfile | CSMS | Default for new transactions; on evseId 0 (all EVSEs) or a specific EVSE. |
TxProfile | CSMS | One specific transaction; requires transactionId and a specific EVSE. |
ChargingStationExternalConstraints | External system (local EMS, grid signal) | Limits from outside OCPP; the CSMS cannot set these, only read them. |
Within a purpose, the profile with the highest stackLevel that is valid at a given moment wins. Across purposes, a TxProfile overrides the TxDefaultProfile for that transaction, and the result is then capped by ChargingStationMaxProfile and any ChargingStationExternalConstraints. The output of this calculation is the composite schedule. The 1.6 names ChargePointMaxProfile became ChargingStationMaxProfile; the rest of the stacking concept is covered with worked examples in 1.6 smart charging.
SetChargingProfile
[2, "scp-301", "SetChargingProfile", {
"evseId": 1,
"chargingProfile": {
"id": 2201,
"stackLevel": 1,
"chargingProfilePurpose": "TxProfile",
"chargingProfileKind": "Relative",
"transactionId": "7f3c2a10-5e61-4b8e-9d2a-0c4b1e8f6a33",
"chargingSchedule": [
{
"id": 1,
"chargingRateUnit": "W",
"chargingSchedulePeriod": [
{ "startPeriod": 0, "limit": 22000.0 }
]
}
]
}
}]
[3, "scp-301", {
"status": "Accepted"
}]Response status is Accepted or Rejected, with optional statusInfo explaining why. A profile with an id that already exists on the station replaces it. Use case K01 has the full list of conditions under which a station must reject a profile; the common ones in the field are a TxProfile with no matching transaction, a ChargingStationMaxProfile on an EVSE other than 0, a stackLevel above SmartChargingCtrlr.ProfileStackLevel, too many periods (PeriodsPerSchedule), or a rate unit the station does not support (SmartChargingCtrlr.RateUnit).
Reading back: GetChargingProfiles and GetCompositeSchedule
GetChargingProfiles (K09) is asynchronous like the device model reports: the CSMS sends criteria and a requestId, the station replies Accepted or NoProfiles, then sends one or more ReportChargingProfiles messages.
[2, "gcp-12", "GetChargingProfiles", {
"requestId": 77,
"evseId": 0,
"chargingProfile": {
"chargingProfilePurpose": "ChargingStationExternalConstraints"
}
}]
[2, "rcp-01", "ReportChargingProfiles", {
"requestId": 77,
"chargingLimitSource": "EMS",
"evseId": 0,
"tbc": false,
"chargingProfile": [
{
"id": 9000,
"stackLevel": 0,
"chargingProfilePurpose": "ChargingStationExternalConstraints",
"chargingProfileKind": "Absolute",
"chargingSchedule": [
{
"id": 1,
"startSchedule": "2026-10-26T12:00:00.000Z",
"chargingRateUnit": "W",
"chargingSchedulePeriod": [
{ "startPeriod": 0, "limit": 80000.0 }
]
}
]
}
]
}]chargingLimitSource (EMS, Other, SO for system operator, CSO for charging station operator) tells you who owns the limit. GetCompositeSchedule (K08) asks the station for the effective result on one EVSE for a duration, optionally in a given chargingRateUnit. Use it to verify that what you think you configured is what the station is actually applying.
[2, "gcs-5", "GetCompositeSchedule", {
"duration": 3600,
"chargingRateUnit": "W",
"evseId": 1
}]
[3, "gcs-5", {
"status": "Accepted",
"schedule": {
"evseId": 1,
"duration": 3600,
"scheduleStart": "2026-10-26T12:10:00.000Z",
"chargingRateUnit": "W",
"chargingSchedulePeriod": [
{ "startPeriod": 0, "limit": 22000.0 }
]
}
}]ClearChargingProfile (K10) removes profiles by chargingProfileId or by chargingProfileCriteria (evseId, chargingProfilePurpose, stackLevel); response Accepted or Unknown.
External limits: NotifyChargingLimit
Many sites have a local energy management system or a grid operator signal that limits the station directly, without going through the CSMS. In 1.6 the CSMS simply never learned about this. In 2.0.1 the station reports it with NotifyChargingLimit, and ClearedChargingLimit when it goes away:
[2, "ncl-3", "NotifyChargingLimit", {
"evseId": 0,
"chargingLimit": {
"chargingLimitSource": "SO",
"isGridCritical": true
},
"chargingSchedule": [
{
"id": 1,
"chargingRateUnit": "W",
"chargingSchedulePeriod": [
{ "startPeriod": 0, "limit": 50000.0 }
]
}
]
}]Show these limits to operators. A support ticket saying "charger only delivers 50 kW" is much faster to close when the dashboard shows a grid-critical limit from the system operator.
ISO 15118: the EV states its needs
With ISO 15118 high-level communication, the EV can tell the station how much energy it wants and when it is leaving. The station forwards this to the CSMS with NotifyEVChargingNeeds (K15, charging with load leveling based on high-level communication):
[2, "nevcn-1", "NotifyEVChargingNeeds", {
"evseId": 1,
"maxScheduleTuples": 3,
"chargingNeeds": {
"requestedEnergyTransfer": "DC",
"departureTime": "2026-10-26T17:30:00.000Z",
"dcChargingParameters": {
"evMaxCurrent": 300,
"evMaxVoltage": 450,
"energyAmount": 42000,
"stateOfCharge": 35
}
}
}]
[3, "nevcn-1", {
"status": "Accepted"
}]requestedEnergyTransfer is DC, AC_single_phase, AC_two_phase or AC_three_phase, with acChargingParameters or dcChargingParameters accordingly. The CSMS responds Accepted, Rejected or Processing, and then sends a TxProfile via SetChargingProfile that meets the departure time within site limits. The station passes it to the EV, and the EV's own chosen plan comes back via NotifyEVChargingSchedule. Renegotiation can be initiated from either side during the session.
Field gotchas
- Amps vs watts. AC stations often only accept
A; DC stations often onlyW. ReadSmartChargingCtrlr.RateUnitand convert in the CSMS, usingnumberPhasesand nominal voltage. - Time zones.
startScheduleis UTC. ADailyrecurring profile meant for local peak hours has to be recalculated when daylight saving time changes. - Minimums. Many EVs stop charging below about 6 A per phase. A limit of 2 A is effectively a pause; some EVs will not resume without replugging. Test with real vehicles.
- Offline. If the station loses the connection mid-session it keeps applying what it has (K06). Make sure your
TxDefaultProfileis a safe fallback.
Next
Next: OCPP 2.0.1 security. Smart charging in roaming is covered in OCPI charging profiles, and bidirectional charging, which OCPP 2.1 adds on top of this model, in V2G and bidirectional charging.

