OCPP MESSAGE · UPDATED 11 AUG 2026

Smart charging: shaping power at the charger

Smart charging is where OCPP stops describing what happened and starts controlling what happens next. It is also the most misunderstood part of the protocol, because a charging profile is not a request for power — it is a ceiling on it.

PART OF THE OCPP COMPLETE GUIDE · 14 MESSAGE GUIDES

IN ONE PARAGRAPH

SetChargingProfile installs a power or current limit at a charger. Profiles stack by purpose and stack level, and the effective limit at any moment is the minimum of every applicable constraint plus whatever the vehicle will accept. GetCompositeSchedule is how you find out what the charger actually thinks it will do.

A profile is a ceiling

The most consequential misunderstanding in this area: setting a limit of 11 kW does not request 11 kW. It forbids more than 11 kW.

The power actually delivered is the minimum of every constraint in play:

actual power = min(
    charging profile limit,
    charge point hardware rating,
    connector / cable rating,
    site grid connection limit,
    what the vehicle asks for      ← often the binding constraint
)

A vehicle at 85% state of charge tapers to a fraction of the connector's capability regardless of any profile. Any product feature, grid commitment or billing assumption built on a profile determining actual draw will be wrong. Verify against MeterValues.

SetChargingProfile

// CSMS -> charge point
[2, "19223220", "SetChargingProfile", {
  "connectorId": 1,
  "csChargingProfiles": {
    "chargingProfileId": 4471,
    "transactionId": 770142,
    "stackLevel": 2,
    "chargingProfilePurpose": "TxProfile",
    "chargingProfileKind": "Relative",
    "chargingSchedule": {
      "duration": 28800,
      "chargingRateUnit": "W",
      "minChargingRate": 1400,
      "chargingSchedulePeriod": [
        { "startPeriod": 0,     "limit": 7400,  "numberPhases": 3 },
        { "startPeriod": 14400, "limit": 22000, "numberPhases": 3 }
      ]
    }
  }
}]

// Charge point -> CSMS
[3, "19223220", { "status": "Accepted" }]

Response is Accepted, Rejected or NotSupported. Smart charging support is genuinely uneven across hardware, so NotSupported is a capability flag to cache per charger model rather than an error to retry.

Purpose and stack level

This is the mechanism that makes OCPP smart charging more capable than OCPI ChargingProfiles, which exposes only one profile per session.

chargingProfilePurposeScopeSet by
ChargePointMaxProfileThe whole charge point, all connectorsThe CPO — site and grid limits
TxDefaultProfileDefault for any transactionThe CPO — standing policy
TxProfileOne specific transactionPer-session control, including from OCPI

stackLevel resolves conflicts within a purpose: higher wins. A TxProfile at stack level 3 overrides one at level 1.

Across purposes, the constraints combine rather than override. A ChargePointMaxProfile capping the site at 50 kW is not overridden by a TxProfile asking for 60 kW — the effective limit remains 50. This is why an eMSP setting a profile through OCPI may see no change at all: the CPO's site cap is already lower, and the eMSP has no visibility into it.

chargingProfileKind

KindstartPeriod is relative to
AbsolutestartSchedule, an explicit wall-clock time
RelativeThe start of the transaction
RecurringA daily or weekly cycle via recurrencyKind

Relative is usually what you want for per-session control — it does not depend on the charger's clock being correct, which given clock drift is a meaningful robustness gain.

GetCompositeSchedule: what the charger actually plans

With several profiles stacked, working out the effective limit by inspection is error-prone. GetCompositeSchedule asks the charger to flatten everything and report the result.

// CSMS -> charge point
[2, "19223221", "GetCompositeSchedule", {
  "connectorId": 1, "duration": 3600, "chargingRateUnit": "W"
}]

// Charge point -> CSMS
[3, "19223221", {
  "status": "Accepted",
  "connectorId": 1,
  "scheduleStart": "2026-08-11T22:00:00Z",
  "chargingSchedule": {
    "duration": 3600,
    "chargingRateUnit": "W",
    "chargingSchedulePeriod": [ { "startPeriod": 0, "limit": 7400 } ]
  }
}]

This is the diagnostic tool for smart charging. When a profile appears to be ignored, this tells you whether the charger received it, how it stacked it, and what limit is actually in force. Use it during commissioning of every new charger model, not only when something breaks.

ClearChargingProfile

Removes profiles by any combination of ID, connector, purpose and stack level:

[2, "19223222", "ClearChargingProfile", {
  "id": 4471
}]

[3, "19223222", { "status": "Accepted" }]

Unknown comes back when nothing matched — which is usually fine, since the goal was for the profile not to be there.

Clearing with no filters removes every profile on the charger, including site-level ChargePointMaxProfile caps. On a site with a constrained grid connection that can take the installation over its limit. Always scope the clear.

Production lessons

  • Always set minChargingRate. Without a floor, an aggressive limit can drop a vehicle into a trickle or cause it to abort the session.
  • Verify against MeterValues. A profile is intent; metering is truth. Alert on sustained divergence to find chargers silently ignoring profiles.
  • Use GetCompositeSchedule when commissioning each model. Stack behaviour varies between vendors more than the spec suggests.
  • Never clear profiles unscoped. You will remove site safety caps.
  • Prefer Relative for per-session profiles to avoid clock-drift dependence.
  • Cache NotSupported per model and stop attempting smart charging where it will never work.
  • Keep site caps in ChargePointMaxProfile, never in per-transaction profiles. A site limit that disappears when a session ends is a dangerous design.

Frequently asked questions

Does an OCPP charging profile request a power level?

No, it sets a ceiling. Actual power is the minimum of the profile limit, the hardware and cable ratings, the site grid limit and what the vehicle asks for. A vehicle near full charge tapers regardless of any profile.

What is stackLevel in OCPP smart charging?

A conflict resolver within a profile purpose — higher stack levels win. Across different purposes, though, constraints combine rather than override, so a site-level ChargePointMaxProfile cap is not overridden by a higher TxProfile limit.

What are the OCPP charging profile purposes?

ChargePointMaxProfile applies to the whole charge point and carries site and grid limits. TxDefaultProfile is the standing default for any transaction. TxProfile applies to one specific transaction and is what per-session control, including from OCPI, uses.

What is GetCompositeSchedule for?

It asks the charger to flatten all stacked profiles and report the limit actually in force. It is the primary diagnostic when a profile appears to be ignored, and it should be used when commissioning every new charger model because stack behaviour varies between vendors.

Why might an OCPI charging profile have no visible effect?

Because the CPO's site-level ChargePointMaxProfile cap is already lower than the limit requested. Constraints across purposes combine rather than override, and an eMSP setting a profile through OCPI has no visibility into the CPO's site caps.