Purpose: Practical reference for AI agents implementing or debugging OCPP 2.1 bidirectional power transfer (V2X). Covers what V2X is, the operation-mode model, setpoints and charge/discharge limits, mode switching and entry/exit flows, frequency support (FCR / aFRR), allowed-energy-transfer negotiation, and offline behavior. Functional Block Q.
Last updated: 2026-06-09
#How This Document Was Produced
This document covers OCPP 2.1 Functional Block Q (Bidirectional Power Transfer / V2X). Its dominant confidence tier is spec-knowledge — behavioral rules summarized from the OCPP 2.1 Edition 2 Part 2 specification, section Q (use cases Q01–Q12). All message names, field names, and enum values are schema-derived: cross-referenced against the mechanically generated Bidirectional schema doc, the SmartCharging schema doc, and the Data Types reference. Where a behavior depends on grid-operator, market, or vendor policy, it is marked as an escalation point rather than asserted.
This document contains 5 escalation points marked with > **ESCALATE: POLICY-DEPENDENT**. When an AI agent encounters one, it MUST stop and ask the developer/operator to make the decision. See METHODOLOGY.md for the full confidence and escalation model.
Companion documents:
- Bidirectional Schemas — field-level schemas for the two Block Q messages (
NotifyAllowedEnergyTransfer,AFRRSignal) - Smart Charging Schemas —
SetChargingProfile,UpdateDynamicSchedule,PullDynamicScheduleUpdate,NotifyEVChargingNeeds, and the charging-profile model V2X builds on (Block K) - Data Types Reference —
OperationModeEnumType,EnergyTransferModeEnumType,ChargingSchedulePeriodType,V2XFreqWattPointType,V2XSignalWattPointType
#1. What V2X Is and Why 2.1 Adds It
Bidirectional power transfer lets an EV not only draw power from the grid but also export power back. OCPP 2.1 introduces this as Functional Block Q. The spec uses the umbrella term V2X ("vehicle-to-anything") rather than V2G, to avoid colliding with ISO 15118's own use of "V2G" for the EV↔Charging-Station link.
V2X variants (all handled identically in OCPP — only the destination of the exported power differs):
| Term | Meaning |
|---|---|
| V2G | Vehicle-to-grid: export power to the electricity grid |
| V2H | Vehicle-to-home: power a home, e.g. during a grid outage or to avoid grid draw |
| V2B | Vehicle-to-building: power a building, same idea at building scale |
| V2L | Vehicle-to-load: power an appliance directly — out of scope for OCPP, no CSMS involvement |
Why it was added: a parked EV is a large battery. Letting it discharge enables grid balancing services (frequency reserves), local load balancing against on-site generation (e.g. solar), backup power, and energy arbitrage — turning charging infrastructure into a flexible grid resource.
#Relationship to ISO 15118-20
V2X over OCPP requires a bidirectional-capable EV-to-station protocol. The spec defines Block Q for use when the EV↔station link is ISO 15118-20 or CHAdeMO. ISO 15118-20 carries the service negotiation (the EV and station agree on a bidirectional energy-transfer service); OCPP carries the authorization of that service and the control loop (setpoints/limits) between station and CSMS. Prerequisite control variables: ISO15118Ctrlr.Enabled = true and V2XChargingCtrlr.Enabled = true.
#Block Q Messages
Only two messages are unique to Block Q. V2X control itself reuses the Smart Charging (Block K) machinery.
| Message | Direction | Purpose |
|---|---|---|
NotifyAllowedEnergyTransfer |
CSMS → CS | Tell the CS which energy-transfer modes are allowed for a transaction (see §6) |
AFRRSignal |
CSMS → CS | Push an aFRR activation signal value to the CS (see §5) |
V2X control is expressed through charging profiles delivered by SetChargingProfile and updated by UpdateDynamicSchedule / PullDynamicScheduleUpdate. The allowed transfer modes are negotiated via NotifyEVChargingNeeds. This document cross-links those rather than duplicating their schemas.
#2. V2X Operation Modes
The mode of operation for each schedule interval is set by the operationMode field of ChargingSchedulePeriodType. The enum is OperationModeEnumType. When operationMode is absent it defaults to ChargingOnly.
The eight values (the first four are shared with regular smart charging; the others are V2X-specific):
operationMode value |
Who determines the control value | Bidirectional? | Notes |
|---|---|---|---|
ChargingOnly |
CS follows limit only |
No | Default. Charge-only; used as a safe starting mode before V2X is authorized. setpoint/dischargeLimit not used. |
ExternalSetpoint |
External actor (e.g. EMS) sets the setpoint | Yes (setpoint may be negative) | CSMS may still bound it with limit and dischargeLimit. |
ExternalLimits |
External actor sets limit and dischargeLimit |
Yes | Like ExternalSetpoint but the limits, not the setpoint, are externally driven. |
CentralSetpoint |
CSMS sets setpoint in the schedule period |
Yes (negative = discharge) | With chargingProfileKind = Dynamic, CSMS updates setpoint via UpdateDynamicSchedule without resending the profile. limit/dischargeLimit are not the control signal (setpoint is); optional bounding still applies. |
CentralFrequency |
CSMS computes setpoint from centrally measured frequency | Yes | For calibrated frequency metering done centrally. Requires chargingProfileKind = Dynamic; CSMS pushes new setpoints continually. If no update arrives in time, the profile terminates and the CS falls back to a lower stack level. |
LocalFrequency |
CS computes setpoint locally from a frequency-watt curve | Yes | FCR / aFRR participation. Requires chargingRateUnit = W. Uses v2xFreqWattCurve (FCR) and/or v2xSignalWattCurve + AFRRSignal (aFRR). See §5. |
LocalLoadBalancing |
CS computes setpoint locally from a metered building load | Yes | EV compensates building load (e.g. against solar). Controlled by configuration keys UpperThreshold, LowerThreshold, UpperOffset, LowerOffset (require UpperThreshold > LowerThreshold). |
Idle |
Neither charge nor discharge | No (suspended) | EV refrains from charging/discharging for the interval. limit, dischargeLimit, setpoint, setpointReactive MUST be absent. Optional battery preconditioning (preconditioningRequest) and EVSE sleep (evseSleep) — see §7. |
ESCALATE: POLICY-DEPENDENT — Which operation modes to enable for a given site or EV is an operator/market decision. Discharging modes may require third-party (eMSP / aggregator / grid-operator) authorization, contracts, or grid-code compliance. Do not enable
*Setpoint,*Frequency, orLocalLoadBalancingmodes by default; confirm the operator's V2X service policy first.
#3. Setpoints and Charge/Discharge Limits
V2X reuses the charging-profile model but extends ChargingSchedulePeriodType with bidirectional fields. All values are in the schedule's chargingRateUnit (Watts or Amperes).
| Field | Sign convention | Meaning |
|---|---|---|
setpoint |
Positive = charge, negative = discharge | Target rate the EV should follow as closely as possible. |
limit |
Positive only | Maximum allowed charging rate. |
dischargeLimit |
Negative only (schema constraint max: 0.0) |
Maximum allowed discharging rate (a floor, since it is negative). |
setpointReactive |
Positive = inductive, negative = capacitive | Reactive-power (or current) setpoint. |
Phase-specific variants exist for AC: setpoint_L2 / setpoint_L3, limit_L2 / limit_L3, dischargeLimit_L2 / dischargeLimit_L3, setpointReactive_L2 / setpointReactive_L3. When the L2/L3 fields are present, the un-suffixed field represents L1; otherwise it represents the sum of all phases.
When a setpoint is given together with limit and/or dischargeLimit, any overshoot while tracking the setpoint must stay within those bounds. Which fields are required vs. ignored depends on operationMode (see the per-mode notes in §2).
Frequency-support curve fields (used by the frequency modes, §5):
| Field | Type | Meaning |
|---|---|---|
v2xFreqWattCurve |
V2XFreqWattPointType[] (1–20 points) |
Power/frequency (FCR) curve: each point is {frequency (Hz), power (W; +charge / −discharge)}. Values between points are linearly interpolated. |
v2xSignalWattCurve |
V2XSignalWattPointType[] (1–20 points) |
Signal/watt (aFRR) curve: each point is {signal (integer), power (W)}. Maps an AFRRSignal.signal value to a power level. |
v2xBaseline |
number | Baseline power on top of which v2xFreqWattCurve / v2xSignalWattCurve outputs are added. |
Note: the JSON schema accepts a single point (
minItems: 1), but a one-point curve yields a fixed output independent of frequency/signal — no interpolation is possible. The spec prose expects at least two points for a meaningful curve.
For the full charging-profile structure, stack-level priority, and chargingProfileKind (Absolute / Recurring / Relative / Dynamic), see the SmartCharging schema doc. V2X does not change those mechanics; it only adds the fields above and the V2X operationMode values.
ESCALATE: POLICY-DEPENDENT — Concrete discharge-limit values (
dischargeLimit) and the maximum export power for a site depend on the grid connection capacity, the EV/battery warranty terms, and any local export agreement. These must come from the operator/grid configuration, not be inferred.
#4. Switching Modes / Entering and Leaving V2X
#4.1 Authorizing and entering V2X (Q01)
Because a V2X energy service often needs third-party authorization that may not complete within the EV's ISO 15118-20 timeout, the recommended pattern is to start in ChargingOnly and renegotiate to V2X once the allowed transfer modes are known (see §4.2). Direct entry (Q01) when V2X is pre-authorized:
| Step | Sender → Receiver | Message | Trigger / Notes |
|---|---|---|---|
| 1 | CS → CSMS | Authorize |
EV plugged in; CS includes the ISO 15118 EVCCID in idToken.additionalInfo. |
| 2 | CSMS → CS | Authorize (response) |
idTokenInfo.status = Accepted, plus the allowedEnergyTransfer list for this EV. |
| 3 | CS → CSMS | TransactionEvent (eventType = Started) |
Transaction begins. |
| 4 | — | (ISO 15118-20 service negotiation) | EV and CS agree on an energy-transfer method. |
| 5 | CS → CSMS | NotifyEVChargingNeeds |
Carries the chosen requestedEnergyTransfer (and optional availableEnergyTransfer list), departureTime, and control mode. |
| 6 | CSMS → CS | NotifyEVChargingNeeds (response) |
status = Accepted (a SetChargingProfile will follow) or NoChargingProfile (CS should use its TxDefaultProfile). |
| 7 | CSMS → CS | SetChargingProfile |
Profile whose schedule has a V2X operationMode (anything other than ChargingOnly). Skipped if step 6 returned NoChargingProfile. |
| 8 | — | (CS → EV) | CS relays charge/discharge parameters to EV; EV requests V2X power transfer; CS accepts. V2X operation active. |
Error handling (Q01): if the CSMS does not accept the requestedEnergyTransfer, it responds to NotifyEVChargingNeeds with status = Rejected and the CS stops the transaction.
#4.2 Safe-start then enable V2X (Q02)
| Step | Sender → Receiver | Message | Trigger / Notes |
|---|---|---|---|
| 1 | CSMS → CS | SetChargingProfile |
Schedule with operationMode = ChargingOnly — transaction starts charge-only while V2X authorization is pending. |
| 2 | CSMS → CS | NotifyAllowedEnergyTransfer |
Once a V2X mode is authorized, CSMS updates the allowed list for the EVSE/transaction (includes a V2X EnergyTransferModeEnumType, e.g. DC_BPT). |
| 3 | CS → CSMS | NotifyAllowedEnergyTransfer (response) |
status = Accepted. |
| 4 | — | (ISO 15118-20 service renegotiation) | EV/CS renegotiate to the V2X service. |
| 5 | CSMS → CS | SetChargingProfile |
New/updated profile with a V2X operationMode; bidirectional operation begins. |
#4.3 Leaving / falling back
A mode change is just a new schedule period or a higher-priority profile expiring. Two key fallbacks:
- Dynamic timeout (
CentralSetpoint/CentralFrequency): if noUpdateDynamicSchedulearrives withinchargingSchedule.duration, the schedule ends and the CS falls back to the next valid (lower stack-level) profile. ForCentralFrequencythis may be aLocalFrequencyprofile, so frequency support continues locally (Q08) until central updates resume. - Offline: see §8.
#5. Frequency Support — FCR and aFRR
Two grid-balancing products are supported, both through frequency-related operation modes. Both require chargingRateUnit = W.
#5.1 FCR (Frequency Containment Reserve), via LocalFrequency
FCR (primary control reserve) reacts automatically within seconds to grid frequency deviations. In OCPP the CS reads grid frequency locally and derives the power setpoint from a power/frequency curve carried in v2xFreqWattCurve. Power for frequencies between curve points is computed by linear interpolation. No per-tick OCPP message is needed once the curve is installed — control is fully local.
#5.2 aFRR (automatic Frequency Restoration Reserve)
aFRR is the secondary reserve; it gradually replaces FCR after ~30 s, must be fully available within 15 minutes once activated (typical TSO/market figures, e.g. ENTSO-E, not OCPP constants), and must track a new setpoint every few seconds (typical TSO/market requirements). Activation comes from the TSO to the operator (CSO), which forwards it to affected stations as an AFRRSignal.
AFRRSignal (CSMS → CS):
| Field | Type | Meaning |
|---|---|---|
signal |
integer | A signal value; the CS maps it to a power level via the v2xSignalWattCurve in the active schedule period. |
timestamp |
date-time | The moment the signal becomes active. |
Response uses GenericStatusEnumType (Accepted / Rejected). The amount of upward/downward aFRR offered by a station is encoded in v2xSignalWattCurve (V2XSignalWattPointType[]): each point maps a signal integer to a power value.
Q07 vs Q08: CentralFrequency (Q07) has the CSMS compute and push the setpoint via UpdateDynamicSchedule (used when calibrated central metering is required); LocalFrequency (Q08) has the CS compute it locally from its curves. Note these V2X frequency modes are distinct from the frequency-droop / frequency-Watt features in Block R (DER Control) — in Block Q frequency support is the profile's primary goal, whereas in Block R it exists to satisfy grid-code requirements.
ESCALATE: POLICY-DEPENDENT — Participation in FCR/aFRR markets, the prequalified power offered, and the contents of
v2xFreqWattCurve/v2xSignalWattCurveare commercial/grid-operator decisions (TSO contracts, prequalification). Do not synthesize curve values or enable frequency modes without the operator's market configuration.
#6. Allowed Energy Transfer
NotifyAllowedEnergyTransfer (CSMS → CS) tells the CS which energy-transfer modes are permitted for a specific transaction. It is sent when the set of allowed modes changes — typically after V2X authorization completes, or whenever an external/aggregating actor updates what this EV may do (the safe-start flow in §4.2).
Request fields:
| Field | Type | Required | Meaning |
|---|---|---|---|
allowedEnergyTransfer |
EnergyTransferModeEnumType[] (minItems 1) |
Yes | The modes the CSMS accepts for this transaction. |
transactionId |
string (≤36) | Yes | The transaction the allowance applies to. |
Response uses NotifyAllowedEnergyTransferStatusEnumType (Accepted / Rejected).
EnergyTransferModeEnumType values (the _BPT suffix denotes Bidirectional Power Transfer; _DER denotes DER-capable; _ACDP is automatic connection device / pantograph):
| Value | Bidirectional? | Notes |
|---|---|---|
AC_single_phase |
No | Unidirectional AC, 1-phase |
AC_two_phase |
No | Unidirectional AC, 2-phase |
AC_three_phase |
No | Unidirectional AC, 3-phase |
DC |
No | Unidirectional DC |
AC_BPT |
Yes | Bidirectional AC |
AC_BPT_DER |
Yes | Bidirectional AC with DER capability |
AC_DER |
No (DER) | AC with DER capability |
DC_BPT |
Yes | Bidirectional DC |
DC_ACDP |
No | DC via automatic connection device (pantograph) |
DC_ACDP_BPT |
Yes | Bidirectional DC via automatic connection device |
WPT |
No | Wireless power transfer |
The same enum also appears in Authorize (the allowedEnergyTransfer returned to the CS) and in NotifyEVChargingNeeds (requestedEnergyTransfer / availableEnergyTransfer), tying authorization, EV negotiation, and the standalone notify message together.
ESCALATE: POLICY-DEPENDENT — Which
EnergyTransferModeEnumTypevalues to place inallowedEnergyTransferfor a given EV/transaction is an authorization/market decision (per-EV contracts, aggregator rules, eMSP approval). Do not default to including_BPTmodes; obtain the operator's allow-list logic.
#7. Idle Mode, Preconditioning, and EVSE Sleep (Q10)
operationMode = Idle requests the EV to neither charge nor discharge for the interval. The fields limit, dischargeLimit, setpoint, and setpointReactive (and their L2/L3 variants) MUST be absent; a SetChargingProfile that includes them with Idle is rejected with status = Rejected, statusInfo.reasonCode = "InvalidSchedule".
Two optional refinements on ChargingSchedulePeriodType during Idle:
| Field | Effect |
|---|---|
preconditioningRequest |
If true, EV keeps the battery preconditioned (optimal temperature) for the interval — may draw some power. |
evseSleep |
If true (and SmartChargingCtrlr.SupportsEvseSleep is true), the EVSE turns off the power electronics/modules for this transaction until an event requires reactivation (e.g. next period's mode change, a new profile including one with 0 W limits, or transaction stop). While sleeping, the CS reports evseSleep = true in TransactionEvent; any charging command — including a 0 W limit/setpoint — wakes it. If evseSleep is unsupported, the CS ignores it and reports evseSleep = false/absent. |
#8. Offline V2X Behavior (Q11 / Q12)
Whether a V2X operation may continue while the CS is offline is governed by two fields on the profile (ChargingProfileType in Block K), not by anything Block-Q-specific:
| Field | Meaning |
|---|---|
maxOfflineDuration |
How long (seconds) the profile stays valid after the CS detects it is offline. The countdown starts at the moment the CS detects the offline condition (expected within ~30 s). |
invalidAfterOfflineDuration |
If true, once maxOfflineDuration has elapsed the profile is permanently invalid and is NOT reactivated when the CS comes back online. |
#8.1 Going offline (Q11)
| Step | Actor | Behavior |
|---|---|---|
| 1 | CS | V2X operation active; CS loses connection to CSMS. |
| 2 | CS | Detects offline; starts the maxOfflineDuration countdown. |
| 3 | CS | While t ≤ maxOfflineDuration: continue the active V2X profile. |
| 4 | CS | When t > maxOfflineDuration: profile becomes invalid; fall back to the next valid (lower stack-level) profile — which may itself be a V2X profile if its own maxOfflineDuration has not elapsed. |
| 5 | CS | If there is no profile to fall back to, continue charging without a profile (charge-only, no limits). |
| 6 | CSMS | On detecting the offline situation, assume the CS has reverted; do not try to compute the exact switch moment from maxOfflineDuration (CS and CSMS detect offline at different instants). |
#8.2 Resuming after offline (Q12)
On reconnection the CS re-evaluates its profiles:
| Case | Condition | Result on reconnect |
|---|---|---|
| 1 | t ≤ maxOfflineDuration |
V2X profile stayed active throughout; nothing changes. |
| 2 | t > maxOfflineDuration, invalidAfterOfflineDuration = false |
CS had fallen back to the lower (charge-only) profile while offline; on reconnect it re-selects the higher V2X profile and resumes V2X. |
| 3 | t > maxOfflineDuration, invalidAfterOfflineDuration = true |
The V2X profile is permanently ineligible; CS continues with the lower charge-only profile. |
ESCALATE: POLICY-DEPENDENT —
maxOfflineDurationandinvalidAfterOfflineDurationfor V2X profiles are risk/operational decisions: how long an EV may keep discharging without CSMS supervision, and whether stale V2X authorization may resume. Set these per the operator's offline-risk policy; do not pick defaults that allow unbounded offline discharge.
#9. Common Pitfalls (interpretation)
- Wrong sign:
setpointanddischargeLimitare negative for discharging;limitis positive-only. Sending a positivedischargeLimitviolates the schema (max: 0.0). Idlewith values: includinglimit/setpoint/etc. withoperationMode = Idleis rejected (InvalidSchedule).- Frequency modes need Watts:
LocalFrequency/CentralFrequencyrequirechargingRateUnit = W. - Dynamic modes need updates:
CentralSetpointandCentralFrequencyrely onchargingProfileKind = Dynamicand timelyUpdateDynamicSchedule; without them the schedule expires and the CS falls back. - Don't treat Block R as Block Q frequency support: DER Control (Block R) frequency-Watt/droop is for grid-code compliance, not V2X market participation.