Purpose: Practical reference for AI agents implementing or debugging OCPP 2.1 DER (Distributed Energy Resource) control — functional block R. Covers what DER control is, the control/curve model, the Get / Set / Clear / Report message flow, alarms and start/stop notifications, prioritization and superseding, and offline behavior.
Last updated: 2026-06-09
#How This Document Was Produced
This document covers OCPP 2.1 DER control (functional block R, use cases R01–R05 of the Part 2 specification). Its dominant confidence tier is spec-knowledge — behavioral rules summarized in original wording from the OCPP 2.1 Edition 2 Part 2 specification. Message names, field names, enum values, and structural constraints are schema-derived — cross-referenced against the DER Control schema reference, the data types reference, and the device model reference, all mechanically extracted from the official OCA artifacts. No spec prose is reproduced verbatim (the OCA specification is CC BY-ND licensed); all explanatory text is original.
This document contains 4 escalation points marked with > **ESCALATE:**. When an AI agent encounters one, it MUST stop and ask the developer (or grid/utility stakeholder) to make the decision. See METHODOLOGY.md for the full confidence and escalation model.
Companion documents:
- DER Control Schemas — complete field-level message and local-type schemas (mechanically generated, high confidence)
- Data Types Reference — shared types including
DERControlEnumTypeandDERControlStatusEnumType - Device Model Reference — the
ACDERCtrlrandDCDERCtrlrcomponents and their variables - Smart Charging Deep-Dive (2.0.1) — charging profiles, which DER control reuses for active/reactive power setpoints
#1. What DER Control Is and Why OCPP 2.1 Adds It
When a charging station (or a fleet of them) charges and discharges bidirectionally, the utility treats it as a Distributed Energy Resource (DER) — a grid-connected inverter that must obey local grid codes. Grid codes define how an inverter reacts to abnormal grid conditions: ride through a voltage sag, trip off on over-frequency, absorb or inject reactive power to support voltage, ramp slowly back into service, and so on. OCPP 2.1 adds functional block R so a CSMS can configure and observe this grid-code behavior on a charging station.
DER control also applies to charging-only stations: a utility may require frequency support (curtailing import when frequency drops) even from stations that never discharge. Throughout block R, "DER control" covers both bidirectional and charging-only cases.
#1.1 The aggregator model
OCPP does not connect a utility directly to a charging station or an EV. The flow is layered:
| Step | Sender → Receiver | Interface | Notes |
|---|---|---|---|
| 1 | Utility → CSMS | IEC 61850 / IEEE 2030.5 / DNP3 / Modbus (out of OCPP scope) | Utility sends grid-code settings, often a schedule of timed events with priorities |
| 2 | CSMS → CS | OCPP block R messages | CSMS, acting as the CSO/aggregator, schedules and prioritizes, then forwards the appropriate controls |
| 3 | CS → EV | ISO 15118-20 (or CHAdeMO) | If the inverter is in the EV, the station relays settings/targets to the EV |
The CSMS carries most of the scheduling and prioritization burden. OCPP block R is the CSMS↔CS interface only.
#1.2 Relationship to ISO 15118-20 inverter architectures
Where the inverter physically lives determines who enforces the grid code. From the OCPP point of view this is irrelevant — the CSMS always sends DER controls to the charging station, which decides how to apply them.
| Architecture | Inverter location | Who enforces grid code | OCPP role |
|---|---|---|---|
| DC bidirectional (ISO 15118-20 DC_BPT, CHAdeMO) | In the EVSE (charging station) | The EVSE inverter directly | CS applies DER controls to its own inverter |
ISO 15118-20 V2G-AC (AC_BPT_DER) |
In the EV | The EV's smart inverter | CS forwards all required settings to the EV during ISO 15118-20 parameter discovery |
ISO 15118-20 V2G-Split (AC_BPT_DER) |
Split EV + EVSE | EV does what it supports; EVSE emulates the rest via ChargeLoop targets |
CS splits controls: EV-supported ones go to the EV, the remainder the EVSE emulates |
The station reports which control modes it can emulate/enforce in the device-model variable ModesSupported (see §9). Active/reactive power setpoints and limits are not block-R messages — they are expressed as OCPP charging profiles (see Smart Charging); block R covers the grid-code behavior (curves and parameter settings) on top of those profiles.
#2. The DER Control Model
A DER control is one configured grid-code behavior. Every control has:
- a
controlId— a unique id (e.g. a UUID, max 36 chars) the CSMS assigns; - a
controlType— one value ofDERControlEnumType, which dictates which control-specific object is allowed; - an
isDefaultflag — default vs scheduled (see §2.4); - a
priorityinteger inside the control-specific object (0 = highest priority); - exactly one control-specific object matching the
controlType(see §2.3).
#2.1 Control types
The 22 values of DERControlEnumType, grouped by what they configure:
| Group | controlType values |
What it does |
|---|---|---|
| Enter service | EnterService |
Voltage/frequency window and delay/ramp for (re)connecting to the grid |
| Frequency droop | FreqDroop, FreqWatt |
Adjust active power as a function of frequency to stabilize the grid |
| Frequency trip / ride-through | HFMustTrip, HFMayTrip, LFMustTrip |
High/low-frequency disconnect (MustTrip) and ride-through (MayTrip) curves |
| Voltage trip / ride-through / momentary cessation | HVMustTrip, HVMayTrip, HVMomCess, LVMustTrip, LVMayTrip, LVMomCess |
High/low-voltage disconnect, ride-through, and momentary-cessation curves |
| Reactive power | FixedVar, VoltVar, WattVar, FixedPFAbsorb, FixedPFInject, WattPF |
Fixed or curve-based reactive-power / power-factor behavior |
| Active power vs voltage | VoltWatt |
Reduce/increase active power as a function of voltage |
| Discharge / power limits | LimitMaxDischarge, PowerMonitoringMustTrip |
Cap discharge power; trip on a power-monitoring threshold |
| Ramp rates | Gradients |
Default and soft-start ramp rates |
ESCALATE: POLICY-DEPENDENT — Which control types are enabled, and the actual curve points / setpoints / thresholds inside them, are grid-code and utility-policy decisions (often per IEEE 1547, EN 50549, VDE-AR-N 4105, or a local regulator). Do not invent curve values; obtain them from the utility/CSO.
#2.2 Curves vs parameter settings
Two structural forms exist:
| Form | Carried in | Used by | Shape |
|---|---|---|---|
| Curve | DERCurveType |
All trip/ride-through and Volt*/Watt*/FreqWatt types |
1–10 (x, y) points (DERCurvePointsType), a priority, and a yUnit (DERUnitEnumType); the x-axis is frequency/voltage/power depending on type |
| Parameter setting | type-specific object (e.g. FreqDroopType, FixedPFType, FixedVarType, EnterServiceType, GradientType, LimitMaxDischargeType) |
FreqDroop, FixedVar, FixedPFAbsorb, FixedPFInject, EnterService, Gradients, LimitMaxDischarge |
Named scalar parameters plus a priority |
A frequency-droop is conceptually a parameterized Freq-Watt curve (slope + dead-band) rather than explicit points, which is why it has its own FreqDroopType object.
Curves may also carry optional refinements: HysteresisType (return-to-normal behavior after an event), VoltageParamsType (e.g. 10-minute mean over-voltage monitoring, momentary cessation via PowerDuringCessationEnumType), and ReactivePowerParamsType (VoltVar vRef / autonomous adjustment).
#2.3 controlType → payload field mapping
SetDERControlRequest carries the control-specific object in exactly one field, selected by controlType. Sending the wrong field, or more than one control, must be rejected (see §4).
controlType value(s) |
Required field in SetDERControlRequest |
|---|---|
FixedPFAbsorb |
fixedPFAbsorb |
FixedPFInject |
fixedPFInject |
FixedVar |
fixedVar |
LimitMaxDischarge |
limitMaxDischarge |
FreqDroop |
freqDroop |
EnterService |
enterService |
Gradients |
gradient |
all other types (trip, ride-through, VoltVar, VoltWatt, WattVar, WattPF, FreqWatt, PowerMonitoringMustTrip) |
curve |
#2.4 Default vs scheduled controls
- Default control (
isDefault = true): always-on baseline for itscontrolType. It is active whenever no scheduled control of the same type is active. A default control must not carrystartTimeorduration— sending those is rejected. - Scheduled control (
isDefault = false): time-bounded bystartTimeandduration(seconds). It becomes active atstartTime, overriding the default of the same type, and is automatically deleted by the station oncestartTime + durationhas elapsed. When it ends, the system falls back to the default (if any).
Two controlTypes are default-only — EnterService and Gradients. The CSMS must not send them with isDefault = false; the station rejects such a request.
Controls persist across reboots/power-cycles — the station stores them durably.
#3. Messages and Direction
Six messages make up block R. Full field-level schemas: DER Control schemas.
| Message | Direction | Purpose |
|---|---|---|
GetDERControl |
CSMS → CS | Request installed controls matching criteria |
SetDERControl |
CSMS → CS | Install or update one DER control |
ClearDERControl |
CSMS → CS | Remove controls by id / type / default flag |
ReportDERControl |
CS → CSMS | Return controls in response to GetDERControl |
NotifyDERAlarm |
CS → CSMS | Report that a control is overriding normal behavior |
NotifyDERStartStop |
CS → CSMS | Report that a scheduled control started or stopped |
All three CSMS → CS responses (Get/Set/Clear) carry a DERControlStatusEnumType status: Accepted, Rejected, NotSupported, or NotFound.
#4. Set Flow
SetDERControl installs or updates a single control. The control-specific field must match controlType (§2.3); the station rejects a request that carries multiple controls or a mismatched field.
#4.1 Setting a default control (e.g. frequency droop)
| Step | Sender → Receiver | Message | Trigger / Notes |
|---|---|---|---|
| 1 | Utility → CSMS | (out of OCPP scope) | New frequency-droop parameters arrive |
| 2 | CSMS → CS | SetDERControlRequest |
isDefault = true, controlType = FreqDroop, freqDroop = { overFreq, underFreq, overDroop, underDroop, responseTime }, no startTime/duration |
| 3 | CS → CSMS | SetDERControlResponse |
status = Accepted |
| 4 | CS (internal) | — | Default droop becomes active immediately |
#4.2 Setting a scheduled control (e.g. VoltVar Q(U) curve)
| Step | Sender → Receiver | Message | Trigger / Notes |
|---|---|---|---|
| 1 | CSMS → CS | SetDERControlRequest |
isDefault = false, controlType = VoltVar, curve = { curveData[], priority, yUnit, startTime, duration } |
| 2 | CS → CSMS | SetDERControlResponse |
status = Accepted |
| 3 | CS → CSMS | NotifyDERStartStopRequest |
At startTime: controlId, started = true |
| 4 | CS (internal) | — | For duration seconds, station adjusts reactive power per the curve |
| 5 | CS → CSMS | NotifyDERStartStopRequest |
At startTime + duration: controlId, started = false; control then deleted |
#4.3 Response rules (SetDERControlResponse)
| Condition | status |
Extra |
|---|---|---|
controlType not supported by the station |
NotSupported |
— |
Default (isDefault=true) sent with startTime and/or duration |
Rejected |
— |
EnterService or Gradients sent with isDefault=false |
Rejected |
— |
Multiple controls, or control object not matching controlType |
Rejected |
— |
| Valid; no existing control of this type | Accepted |
— |
| Valid; supersedes existing control(s) of same type | Accepted |
supersededIds[] lists the superseded controlIds |
The supersededIds array (1–24 ids) appears whenever installing this control causes others of the same type to be superseded — see §6.
#5. Get / Report and Clear Flows
#5.1 Get / Report
GetDERControl carries a requestId and optional filters (controlId, controlType, isDefault). A missing filter matches any value. The station answers the request synchronously with a GetDERControlResponse status, then streams the matching controls in one or more asynchronous ReportDERControlRequest messages (CS → CSMS), each echoing the original requestId.
| Step | Sender → Receiver | Message | Trigger / Notes |
|---|---|---|---|
| 1 | CSMS → CS | GetDERControlRequest |
requestId + optional controlId / controlType / isDefault |
| 2 | CS → CSMS | GetDERControlResponse |
status = Accepted if matches exist; see table below |
| 3 | CS → CSMS | ReportDERControlRequest (1..n) |
Same requestId; tbc = true on every message except the last |
| 4 | CSMS → CS | ReportDERControlResponse |
Empty {} ack for each report |
GetDERControlResponse status:
| Condition | status |
|---|---|
No controls match the given isDefault / controlType / controlId |
NotFound |
controlType is one the station does not support |
NotSupported |
| One or more controls match | Accepted (reports follow) |
ReportDERControlRequest groups returned controls by type into arrays of "Get" wrapper types — DERCurveGetType, FreqDroopGetType, FixedPFGetType, FixedVarGetType, EnterServiceGetType, GradientGetType, LimitMaxDischargeGetType. Each wrapper adds the id (the original controlId), isDefault, and an isSuperseded flag, so the CSMS can see which installed controls are currently shadowed by a higher-priority one.
#5.2 Clear
ClearDERControl removes controls. isDefault is required (clear defaults vs scheduled); controlId and controlType are optional filters.
| Step | Sender → Receiver | Message | Trigger / Notes |
|---|---|---|---|
| 1 | CSMS → CS | ClearDERControlRequest |
isDefault required; optional controlId / controlType |
| 2 | CS → CSMS | ClearDERControlResponse |
status per table below |
| Condition | status |
|---|---|
controlType set + not supported by station |
NotSupported |
controlType given but never set for that isDefault |
NotFound |
controlId given but never set for that isDefault |
NotFound |
No controlType/controlId → clear all controls matching isDefault |
Accepted |
controlType matches set controls → clear them for that isDefault |
Accepted |
controlId matches a set control → clear it for that isDefault |
Accepted |
#6. Prioritization and Superseding
Two mechanisms decide which control of a given type is active. Type here means a specific control parameter or curve type (e.g. FreqDroop, HFMustTrip).
- Default vs scheduled. A scheduled control of a type, while active, overrides the default of that type. Outside any scheduled window, the default applies.
priorityvalue. Only one control of a type can be active at a time. When multiple exist, the one with the lowestpriorityvalue wins (0 = highest priority). This applies independently within defaults and within scheduled controls.
#6.1 Superseding rules
Prioritization happens when the message is received, not at start time. Key rules:
| Situation | Behavior |
|---|---|
New control of a type has a lower priority value than an existing one not yet started |
Existing control is superseded immediately (isSuperseded = true), even if the new control starts much later |
New higher-priority control arrives while a lower-priority control of the same type is already active (past startTime) |
Active control keeps running until the new control's startTime, then is superseded |
New control has a higher priority value than an already-active control of the same type |
New control is accepted but immediately superseded; the existing one keeps running. Its controlId is returned in supersededIds. (The CSMS should avoid sending lower-priority controls in the first place.) |
Any control with isSuperseded = true |
Never executed |
Any control past startTime + duration |
Automatically deleted by the station |
When no scheduled control of a type is active, the station executes the default control of that type that has isSuperseded = false.
This matches the prioritization process in the IEEE 2030.5 / CSIP profile, so a CSMS can map utility events to OCPP controls predictably. Ideally the CSMS resolves priority itself and sends only the winning control, but because network latency makes "send exactly at start time" unreliable, the station must also handle overlapping controls of differing priority.
ESCALATE: POLICY-DEPENDENT — Assigning
priorityvalues across overlapping utility events (which event group outranks another) is a CSO/utility scheduling decision. Confirm the priority scheme with the operator before relying on superseding behavior.
#7. Alarms and Start/Stop Notifications
#7.1 NotifyDERAlarm — a control overrides normal behavior
When a station starts deviating from normal (dis)charging because a DER curve or setting forced it to — for example an over-frequency causing an HFMustTrip curve to cut export — it raises a NotifyDERAlarm so the CSO is aware.
| Field | Use |
|---|---|
controlType |
Which control took over (e.g. HFMustTrip, LimitMaxDischarge, VoltVar) |
timestamp |
When the event started (or ended) |
alarmEnded |
Absent/false when the alarm starts; true on the follow-up message when the condition clears |
gridEventFault |
Optional cause, one of GridEventFaultEnumType (e.g. OverFrequency, UnderVoltage, OverCurrent, LocalEmergency) |
extraInfo |
Optional free text (max 200), e.g. forwarded from the EV |
The station sends the alarm again with alarmEnded = true when the event ends. A purely reactive-power curve (e.g. VoltVar) typically does not raise an alarm, because it does not disturb the active-power profile — unless the active charging profile also specifies reactive-power behavior.
#7.2 NotifyDERStartStop — scheduled control activation
When a scheduled control (isDefault = false, isSuperseded = false) reaches its startTime or its startTime + duration, the station reports the transition with NotifyDERStartStop.
| Field | Use |
|---|---|
controlId |
The control that started/stopped (matches the SetDERControlRequest id) |
started |
true at startTime, false at startTime + duration |
timestamp |
Current time of the transition |
supersededIds |
If starting this control supersedes others of the same type, their ids (1–24) |
| Trigger | Message contents |
|---|---|
Scheduled control reaches startTime |
started = true, controlId |
| ...and it supersedes an active control B | started = true, controlId = A, supersededIds = [B] |
Scheduled control reaches startTime + duration |
started = false, controlId |
NotifyDERAlarm and NotifyDERStartStop are distinct: start/stop reports the schedule lifecycle of a control; alarm reports that a control is actively overriding charging because of a grid event.
#8. Offline Behavior
Block R has no offline-specific messages. DER controls are stored persistently on the station, so a reboot or connectivity loss does not erase them — defaults and scheduled controls keep applying on their own timelines, and the station continues enforcing grid-code behavior autonomously (that is the point of curves: autonomous reaction without a round-trip to the CSMS).
Active/reactive power setpoints, by contrast, ride on OCPP charging profiles, whose offline lifetime is governed by maxOfflineDuration / invalidAfterOfflineDuration in ChargingProfileType (V2X use cases Q11/Q12, outside block R). See the Smart Charging deep-dive for that mechanism.
ESCALATE: SPEC-SILENT — The Part 2 DER chapter does not define a block-R-specific reconciliation procedure for what the CSMS should re-
Getor re-Setafter a station reconnects following a long outage (e.g. whether scheduled controls that elapsed while offline are reported as deleted). Confirm the expected reconciliation with the integration team.
#9. Device Model: DCDERCtrlr & ACDERCtrlr
DER capabilities and the set of supported control modes live in two device-model components (see the Device Model reference). Both sit at the EVSE level.
| Component | Represents | Key variables |
|---|---|---|
DCDERCtrlr |
DER capabilities ("nameplate") of the EVSE's own DC inverter | Enabled, ModesSupported, ratings (MaxW, MaxVA, MaxVar, MaxVarNeg, MaxChargeRateW, over/under-excited W and PF), voltage ratings (VNom, MaxV, MinV), inverter identity (InverterManufacturer/Model/SerialNumber/SwVersion/HwVersion), IslandingDetectionMethod, ReactiveSusceptance |
ACDERCtrlr |
DER modes the EVSE can emulate via ISO 15118-20 ChargeLoop to control the EV's inverter |
ModesSupported |
ModesSupported (a MemberList) is the contract for SetDERControl/GetDERControl: the CSMS should not send (and the station will answer NotSupported for) a controlType absent from ModesSupported of the relevant controller. For a DC station the supported modes are the EVSE inverter's; for an AC station they are the modes the EVSE can emulate (the rest must be handled by the EV's inverter, per the V2G-AC / V2G-Split split in §1.2).
ESCALATE: POLICY-DEPENDENT —
Enabledand the contents ofModesSupported, plus all nameplate ratings, reflect hardware capability and regulatory registration of the inverter. Treat them as configuration provided by the station vendor / CSO, not values to set arbitrarily.
#10. Use Case Index
The block-R use cases (R01–R05) in the Part 2 specification map to this document as:
| Use case | Topic | Section(s) |
|---|---|---|
| R01 | Start V2X session with DER control in the EVSE (DC / AC emulation) | §1.2, §7 |
| R02 | Start V2X session with DER control in the EV (ISO 15118-20 AC_BPT_DER) |
§1.2 |
| R03 | Hybrid DER control split across EV and EVSE | §1.2 |
| R04 | Configure DER control settings (Set / Get / Report / Clear, start/stop) | §4, §5, §6, §7 |
| R05 / device model | Reporting DER capabilities | §9 |