OCPP 2.1 Edition 2 Section Q

Bidirectional Power Transfer (V2X) - CSMS Developer Guide

Based on OCPP 2.1 Edition 2 Specification (Part 2), Section Q (Bidirectional Power Transfer). This guide covers all V2X flows (Q01–Q12), including V2X authorization, central and external setpoint control, frequency support, local load balancing, idle mode, and offline handling from the CSMS perspective using OCPP-J (JSON over WebSocket).

18 Sections
12 Use Cases
Q01 – Q12

1. Overview & Terminology

Introduction

V2X (Vehicle-to-Anything) is bidirectional power transfer between an EV and external systems. This section covers all V2X flows from the CSMS perspective, including authorization, setpoint control, frequency support, load balancing, and offline handling.

What is V2X?

V2G (Vehicle-to-Grid)

Bidirectional power transfer between an EV and the electrical grid.

V2H (Vehicle-to-Home)

Bidirectional power transfer between an EV and a home.

V2B (Vehicle-to-Building)

Bidirectional power transfer between an EV and a building.

Note: V2L (Vehicle-to-Load) is NOT relevant to OCPP as it does not involve OCPP communication.

Prerequisites

The Charging Station must have the following configuration for V2X operations:

Required Configuration

  • ISO15118Ctrlr.Enabled = true
  • V2XChargingCtrlr.Enabled = true

Capability Reporting

  • V2XChargingCtrlr.V2XSupportedOperationModes
  • V2XChargingCtrlr.SupportedEnergyTransferModes

Sign Convention

Value Meaning
Positive setpoint Charging (grid → EV)
Negative setpoint Discharging (EV → grid)
Positive limit Maximum allowed charging power (always positive)
Negative dischargeLimit Maximum allowed discharging power (always negative, e.g. -5000 W)

CSMS Role Summary

The CSMS is responsible for the following V2X operations:

  1. Authorizing V2X operations (providing allowedEnergyTransfer list)
  2. Responding to NotifyEVChargingNeedsRequest from Charging Stations
  3. Sending SetChargingProfileRequest with V2X-enabled charging schedules
  4. Dynamically updating setpoints via UpdateDynamicScheduleRequest
  5. Responding to PullDynamicScheduleUpdateRequest with updated parameters
  6. Sending AFRRSignalRequest for frequency regulation
  7. Sending NotifyAllowedEnergyTransferRequest to update allowed energy transfers mid-session
  8. Handling NotifyChargingLimitRequest from Charging Stations (external system limits)
  9. Handling NotifyEVChargingScheduleRequest from Charging Stations
  10. Handling TransactionEventRequest messages with V2X-specific fields

2. V2X Operation Modes Reference

Reference

Each ChargingSchedulePeriodType can specify an operationMode. These are defined in OperationModeEnumType.

Mode Reference

Mode Description Who Controls? CSMS Fields
ChargingOnly Default. Charging only, no discharging. N/A limit (required)
CentralSetpoint CSMS provides power setpoint. CSMS setpoint (required), optionally limit, dischargeLimit
ExternalSetpoint External system (e.g. EMS) provides setpoint. External System setpoint set externally; CSMS optionally sets limit, dischargeLimit
ExternalLimits External system provides limits. External System limit, dischargeLimit set externally
CentralFrequency CSMS provides setpoint for frequency support. CSMS (dynamic) setpoint (required, updated via UpdateDynamicScheduleRequest)
LocalFrequency CS uses local frequency readings + curves. Charging Station v2xFreqWattCurve, v2xBaseline, optionally v2xSignalWattCurve
LocalLoadBalancing CS reads upstream meter, adjusts setpoint. Charging Station Thresholds configured via device model
Idle EV should not charge or discharge. N/A No limit/setpoint/dischargeLimit

Limits & Setpoints per Operation Mode

Mode limit dischargeLimit setpoint setpointReactive
ChargingOnly required - - -
CentralSetpoint optional optional required optional
CentralFrequency optional optional required -
LocalFrequency - - calculated from freq/signal curves -
ExternalSetpoint optional optional set externally -
ExternalLimits set externally set externally - -
LocalLoadBalancing - - calculated from load and thresholds -

3. Key Data Types & Enumerations

Reference

EnergyTransferModeEnumType

Used in allowedEnergyTransfer and requestedEnergyTransfer:

EnergyTransferModeEnumType
"AC_single_phase"    - AC single-phase charging only
"AC_two_phase"       - AC two-phase charging only
"AC_three_phase"     - AC three-phase charging only
"DC"                 - DC charging only
"AC_BPT"             - AC Bidirectional Power Transfer
"AC_BPT_DER"         - AC BPT with DER (Distributed Energy Resource)
"AC_DER"             - AC with DER
"DC_BPT"             - DC Bidirectional Power Transfer
"DC_ACDP"            - DC with ACDP
"DC_ACDP_BPT"        - DC ACDP Bidirectional
"WPT"                - Wireless Power Transfer

Bidirectional modes: AC_BPT, AC_BPT_DER, DC_BPT, DC_ACDP_BPT

OperationModeEnumType

OperationModeEnumType
"Idle"                 - No charging/discharging
"ChargingOnly"         - Only charging allowed (default)
"CentralSetpoint"      - CSMS controls setpoint
"ExternalSetpoint"     - External actor controls setpoint
"ExternalLimits"       - External actor controls limits
"CentralFrequency"     - CSMS controls frequency support
"LocalFrequency"       - Local frequency measurements
"LocalLoadBalancing"   - Local load balancing

ChargingProfilePurposeEnumType (V2X relevant)

ChargingProfilePurposeEnumType
"TxProfile"           - Per-transaction profile (V2X operations)
"TxDefaultProfile"    - Default per-transaction profile
"ChargingStationExternalConstraints" - External system constraints

ChargingProfileKindEnumType

ChargingProfileKindEnumType
"Absolute"   - Fixed time schedule
"Recurring"  - Recurring schedule (daily/weekly)
"Relative"   - Relative to transaction start
"Dynamic"    - Single period, updated dynamically

V2X Point Types

V2XFreqWattPointType
{
  "frequency": 50.0,     // Net frequency in Hz (number, required)
  "power": 0             // Power in W: positive=charge, negative=discharge (number, required)
}
V2XSignalWattPointType
{
  "signal": 0,           // Signal value from AFRRSignalRequest (integer, required)
  "power": 0             // Power in W: positive=charge, negative=discharge (number, required)
}

Power.Active.Residual Measurand

The CSMS can monitor how well the Charging Station follows a setpoint using this measurand:

Residual Calculation
If Power.Active.Setpoint is None:    Residual = 0
If Power.Active.Setpoint == 0:       Residual = Power.Active.Import + Power.Active.Export
If Power.Active.Setpoint > 0:        Residual = Power.Active.Import - Power.Active.Setpoint
If Power.Active.Setpoint < 0:        Residual = Power.Active.Export + Power.Active.Setpoint

Positive Residual

Charging/discharging at higher power than setpoint.

Negative Residual

Charging/discharging at lower power than setpoint.

4. Q01 — V2X Authorization

CS-Initiated
Use Case ID Q01
Objective Authorize an EV for V2X power transfer and start a V2X session
Direction CS → CSMS (CS initiates)
Key Messages AuthorizeRequest, TransactionEventRequest, NotifyEVChargingNeedsRequest, SetChargingProfileRequest

Step 1: Handle AuthorizeRequest (CS → CSMS)

The Charging Station sends an authorization request. For V2X sessions, the CS may include an EVCCID in additionalInfo.

Incoming AuthorizeRequest
{
  "idToken": {
    "idToken": "RFID12345",
    "type": "ISO14443",
    "additionalInfo": [
      {
        "additionalIdToken": "<EVCCID>",
        "type": "EVCCID"
      }
    ]
  }
}

When CSMS can determine allowed energy transfers immediately:

AuthorizeResponse — With V2X permissions
{
  "idTokenInfo": {
    "status": "Accepted"
  },
  "allowedEnergyTransfer": ["DC", "DC_BPT"]
}

When CSMS cannot determine allowed energy transfers yet (e.g. awaiting third-party approval):

AuthorizeResponse — Without V2X permissions (deferred)
{
  "idTokenInfo": {
    "status": "Accepted"
  }
}

Requirement Q01.FR.01: When ISO15118Ctrlr.Enabled = true AND V2XChargingCtrlr.Enabled = true AND CSMS can determine it, CSMS SHALL return allowedEnergyTransfer in AuthorizeResponse.

Requirement Q01.FR.08: If CSMS cannot determine allowedEnergyTransfer in time, omit it. The CS will default to charging-only behavior.

AuthorizeResponse Schema (relevant fields)
{
  "idTokenInfo": {                          // required
    "status": AuthorizationStatusEnumType   // required: "Accepted", "Blocked", etc.
  },
  "allowedEnergyTransfer": [               // optional array of EnergyTransferModeEnumType
    "DC", "DC_BPT", "AC_BPT", ...
  ]
}

Step 2: Handle TransactionEventRequest (CS → CSMS)

The CS sends this after authorization with eventType = Started. For V2X sessions, the CS adds the EVCCID to idToken.additionalInfo.

TransactionEventResponse
{}

The response body has no required fields.

Step 3: Handle NotifyEVChargingNeedsRequest (CS → CSMS)

This is the critical message where the Charging Station reports the EV's charging needs, including V2X parameters.

Incoming NotifyEVChargingNeedsRequest
{
  "evseId": 1,
  "chargingNeeds": {
    "requestedEnergyTransfer": "DC_BPT",
    "availableEnergyTransfer": ["DC", "DC_BPT"],
    "controlMode": "DynamicControl",
    "departureTime": "2026-02-17T18:00:00Z",
    "v2xChargingParameters": {
      "minChargePower": 500,
      "maxChargePower": 11000,
      "minDischargePower": 500,
      "maxDischargePower": 11000,
      "maxChargeCurrent": 32,
      "maxDischargeCurrent": 32,
      "minVoltage": 230,
      "maxVoltage": 400,
      "evTargetEnergyRequest": 20000,
      "evMinEnergyRequest": 5000,
      "evMaxEnergyRequest": 40000,
      "evMinV2XEnergyRequest": -15000,
      "evMaxV2XEnergyRequest": 10000,
      "targetSoC": 80
    }
  }
}

NotifyEVChargingNeedsResponse

Scenario status value Meaning
CSMS accepts and can provide profile now Accepted CS expects a SetChargingProfileRequest soon
CSMS accepts but needs time Processing CS expects a SetChargingProfileRequest later
CSMS accepts but uses TxDefaultProfile NoChargingProfile No SetChargingProfileRequest will follow
CSMS rejects requested energy transfer Rejected CS will stop the transaction
Response — Accept
{
  "status": "Accepted"
}
Response — Reject
{
  "status": "Rejected"
}

Requirement Q01.FR.04: If CSMS does not accept the requestedEnergyTransfer, respond with status = Rejected.

Requirement Q01.FR.07: If CSMS accepts, respond with Accepted (profile ready), Processing (need more time), or NoChargingProfile (use TxDefaultProfile).

Step 4: Send SetChargingProfileRequest (CSMS → CS)

After accepting the charging needs, send a V2X charging profile:

SetChargingProfileRequest — V2X Profile
{
  "evseId": 1,
  "chargingProfile": {
    "id": 100,
    "stackLevel": 2,
    "chargingProfilePurpose": "TxProfile",
    "chargingProfileKind": "Absolute",
    "transactionId": "tx-abc-123",
    "chargingSchedule": [
      {
        "id": 1,
        "chargingRateUnit": "W",
        "chargingSchedulePeriod": [
          {
            "startPeriod": 0,
            "operationMode": "CentralSetpoint",
            "limit": 11000,
            "dischargeLimit": -11000,
            "setpoint": 5000
          }
        ]
      }
    ]
  }
}
Response — Accepted
{
  "status": "Accepted"
}
Response — Rejected
{
  "status": "Rejected",
  "statusInfo": {
    "reasonCode": "InvalidSchedule",
    "additionalInfo": "setpoint outside limit/dischargeLimit range"
  }
}

Step 5 (Optional): Update Allowed Energy Transfer Mid-Session

If V2X authorization arrives later (e.g. third-party approval), send NotifyAllowedEnergyTransferRequest:

NotifyAllowedEnergyTransferRequest
{
  "transactionId": "tx-abc-123",
  "allowedEnergyTransfer": ["DC", "DC_BPT"]
}
NotifyAllowedEnergyTransferResponse
{
  "status": "Accepted"
}
NotifyAllowedEnergyTransferRequest Schema
{
  "transactionId": string (max 36, required)   // Transaction ID
  "allowedEnergyTransfer": [                    // required, min 1 item
    EnergyTransferModeEnumType
  ]
}

Requirement Q02.FR.05: When CSMS changes the list of allowed energy transfers for a transaction, CSMS SHALL send NotifyAllowedEnergyTransferRequest.

Error Handling: If the requestedEnergyTransfer from NotifyEVChargingNeedsRequest is not accepted, respond with Rejected and the CS will stop the current transaction.

5. Q02 — Starting in ChargingOnly Before Enabling V2X

CSMS-Initiated
Use Case ID Q02
Objective Start a transaction in ChargingOnly mode and upgrade to V2X later
When to Use When the CSMS is unsure during energy service negotiation whether V2X is allowed

Steps 1–3: Initial ChargingOnly Setup

Step 1: Handle AuthorizeRequest — Omit allowedEnergyTransfer

AuthorizeResponse — Without V2X permissions
{
  "idTokenInfo": {
    "status": "Accepted"
  }
}

Step 2: Handle NotifyEVChargingNeedsRequest

The CS will send requestedEnergyTransfer set to its default (charging-only, e.g. DC or AC_single_phase).

NotifyEVChargingNeedsResponse
{
  "status": "Accepted"
}

Step 3: Send SetChargingProfileRequest with ChargingOnly

SetChargingProfileRequest — ChargingOnly
{
  "evseId": 1,
  "chargingProfile": {
    "id": 50,
    "stackLevel": 1,
    "chargingProfilePurpose": "TxProfile",
    "chargingProfileKind": "Absolute",
    "transactionId": "tx-abc-123",
    "chargingSchedule": [{
      "id": 1,
      "chargingRateUnit": "W",
      "chargingSchedulePeriod": [{
        "startPeriod": 0,
        "operationMode": "ChargingOnly",
        "limit": 11000
      }]
    }]
  }
}

Requirement Q02.FR.01: When CS does not request bidirectional transfer, CSMS SHALL send SetChargingProfileRequest with operationMode = ChargingOnly (or omit it, as ChargingOnly is the default).

Requirement Q02.FR.02: In ChargingOnly mode, CSMS SHALL NOT include dischargeLimit, setpoint, or setpointReactive.

Steps 4–6: Enable V2X Later

Step 4: Determine V2X Permission (async)

Use the EVCCID from additionalInfo in the AuthorizeRequest or from ConnectedEV.VehicleId device model variable. Optionally check the vehicle certificate from ConnectedEV.VehicleCertificate.

Step 5: Send NotifyAllowedEnergyTransferRequest to Enable V2X

NotifyAllowedEnergyTransferRequest
{
  "transactionId": "tx-abc-123",
  "allowedEnergyTransfer": ["DC", "DC_BPT"]
}

This triggers a service renegotiation between CS and EV. The CS will then send a new NotifyEVChargingNeedsRequest with the updated requestedEnergyTransfer.

Step 6: Handle New NotifyEVChargingNeedsRequest and Send V2X Profile

Respond with Accepted and follow up with a V2X-enabled SetChargingProfileRequest (as in Q01 Step 4).

6. Q03 — Central V2X Control with Charging Schedule

CSMS-Initiated
Use Case ID Q03
Objective CSMS controls EV charge/discharge behavior via a power profile with scheduled periods using CentralSetpoint mode
Prerequisites Profile purpose: TxProfile or TxDefaultProfile. Transaction must be active with V2X authorization.

Scheduled Mode (Multiple Periods)

SetChargingProfileRequest — Scheduled CentralSetpoint
{
  "evseId": 1,
  "chargingProfile": {
    "id": 200,
    "stackLevel": 2,
    "chargingProfilePurpose": "TxProfile",
    "chargingProfileKind": "Absolute",
    "transactionId": "tx-abc-123",
    "chargingSchedule": [{
      "id": 1,
      "chargingRateUnit": "W",
      "startSchedule": "2026-02-17T08:00:00Z",
      "chargingSchedulePeriod": [
        {
          "startPeriod": 0,
          "operationMode": "CentralSetpoint",
          "setpoint": 7000,
          "limit": 11000,
          "dischargeLimit": -5000
        },
        {
          "startPeriod": 7200,
          "operationMode": "CentralSetpoint",
          "setpoint": -3000,
          "limit": 11000,
          "dischargeLimit": -5000
        },
        {
          "startPeriod": 14400,
          "operationMode": "CentralSetpoint",
          "setpoint": 5000,
          "limit": 11000,
          "dischargeLimit": -5000
        }
      ]
    }]
  }
}

Requirement Q03.FR.01: CSMS SHALL send SetChargingProfileRequest with operationMode = CentralSetpoint.

Requirement Q03.FR.02: CSMS SHALL provide a value for setpoint (optionally L2 and L3 variants).

Requirement Q03.FR.03: CSMS MAY include limit and/or dischargeLimit to constrain the setpoint range.

Dynamic Mode Variant

If chargingProfileKind = Dynamic, the CSMS can update the setpoint without sending a new profile:

SetChargingProfileRequest — Dynamic CentralSetpoint
{
  "evseId": 1,
  "chargingProfile": {
    "id": 201,
    "stackLevel": 2,
    "chargingProfilePurpose": "TxProfile",
    "chargingProfileKind": "Dynamic",
    "transactionId": "tx-abc-123",
    "chargingSchedule": [{
      "id": 1,
      "chargingRateUnit": "W",
      "chargingSchedulePeriod": [{
        "startPeriod": 0,
        "operationMode": "CentralSetpoint",
        "setpoint": 5000,
        "limit": 11000,
        "dischargeLimit": -5000
      }]
    }]
  }
}

Then update dynamically with UpdateDynamicScheduleRequest (see Q04).

7. Q04 — Central V2X Control with Dynamic CSMS Setpoint

CSMS-Initiated
Use Case ID Q04
Objective CSMS dynamically controls the setpoint in real-time, updating it frequently
Prerequisites Profile purpose: TxProfile or TxDefaultProfile. Profile kind: Dynamic.

Step 1: Send Initial SetChargingProfileRequest

SetChargingProfileRequest — Dynamic Profile
{
  "evseId": 1,
  "chargingProfile": {
    "id": 300,
    "stackLevel": 2,
    "chargingProfilePurpose": "TxProfile",
    "chargingProfileKind": "Dynamic",
    "transactionId": "tx-abc-123",
    "dynUpdateInterval": 60,
    "chargingSchedule": [{
      "id": 1,
      "chargingRateUnit": "W",
      "duration": 120,
      "chargingSchedulePeriod": [{
        "startPeriod": 0,
        "operationMode": "CentralSetpoint",
        "setpoint": 5000
      }]
    }]
  }
}

Key Fields

  • chargingProfileKind: Dynamic (required)
  • dynUpdateInterval: seconds between pull updates from CS (optional, 0 = no pulling)
  • chargingSchedule.duration: if set, schedule expires after this many seconds without update

Step 2a: Push Updates via UpdateDynamicScheduleRequest (CSMS → CS)

UpdateDynamicScheduleRequest
{
  "chargingProfileId": 300,
  "scheduleUpdate": {
    "setpoint": 2000
  }
}
UpdateDynamicScheduleRequest Schema
{
  "chargingProfileId": integer (required)       // ID of the dynamic charging profile
  "scheduleUpdate": {                           // required
    "limit": number,                            // optional
    "limit_L2": number,                         // optional
    "limit_L3": number,                         // optional
    "dischargeLimit": number (max 0),           // optional, negative values
    "dischargeLimit_L2": number (max 0),        // optional
    "dischargeLimit_L3": number (max 0),        // optional
    "setpoint": number,                         // optional
    "setpoint_L2": number,                      // optional
    "setpoint_L3": number,                      // optional
    "setpointReactive": number,                 // optional
    "setpointReactive_L2": number,              // optional
    "setpointReactive_L3": number               // optional
  }
}
UpdateDynamicScheduleResponse
{
  "status": "Accepted"
}

Step 2b: Handle Pull Updates via PullDynamicScheduleUpdateRequest (CS → CSMS)

When dynUpdateInterval is set, the CS pulls updates at that interval.

Incoming PullDynamicScheduleUpdateRequest
{
  "chargingProfileId": 300
}
PullDynamicScheduleUpdateResponse
{
  "status": "Accepted",
  "scheduleUpdate": {
    "setpoint": 2000
  }
}
PullDynamicScheduleUpdateResponse Schema
{
  "status": "Accepted" | "Rejected" (required)
  "scheduleUpdate": {                           // optional (only when Accepted)
    "limit": number,
    "limit_L2": number,
    "limit_L3": number,
    "dischargeLimit": number (max 0),
    "dischargeLimit_L2": number (max 0),
    "dischargeLimit_L3": number (max 0),
    "setpoint": number,
    "setpoint_L2": number,
    "setpoint_L3": number,
    "setpointReactive": number,
    "setpointReactive_L2": number,
    "setpointReactive_L3": number
  },
  "statusInfo": {                               // optional
    "reasonCode": string (max 20),
    "additionalInfo": string (max 1024)
  }
}

Duration / Fallback Behavior

If chargingSchedule.duration is set and no update (SetChargingProfileRequest, UpdateDynamicScheduleRequest, or PullDynamicScheduleUpdate) is received within duration seconds, the charging profile expires and the CS falls back to the next valid profile at a lower stack level.

8. Q05 — External V2X Setpoint Control with Charging Profile from CSMS

CSMS-Initiated
Use Case ID Q05
Objective CSMS delegates real-time power control to an External System (e.g. EMS) while retaining control over the charging profile structure
Prerequisites ExternalControlSignalsEnabled = true, ExternalConstraintsProfileDisallowed = true, Profile kind: Dynamic

CSMS Action: Send SetChargingProfileRequest

ExternalSetpoint Mode

SetChargingProfileRequest — ExternalSetpoint
{
  "evseId": 1,
  "chargingProfile": {
    "id": 400,
    "stackLevel": 2,
    "chargingProfilePurpose": "TxProfile",
    "chargingProfileKind": "Dynamic",
    "transactionId": "tx-abc-123",
    "chargingSchedule": [{
      "id": 1,
      "chargingRateUnit": "W",
      "duration": 3600,
      "chargingSchedulePeriod": [{
        "startPeriod": 0,
        "operationMode": "ExternalSetpoint",
        "setpoint": 0,
        "limit": 11000,
        "dischargeLimit": -5000
      }]
    }]
  }
}

ExternalLimits Mode

ChargingSchedulePeriod — ExternalLimits
{
  "operationMode": "ExternalLimits",
  "limit": 11000,
  "dischargeLimit": -5000
}

Behavior

ExternalSetpoint

The External System controls setpoint and setpointReactive. CSMS optionally provides limit and dischargeLimit.

ExternalLimits

The External System controls limit and dischargeLimit. Setpoint is not used.

For Dynamic profiles, the External System can update values dynamically via the Charging Station's local interface.

The CS updates dynUpdateTime whenever it receives an external update.

If duration is set and no update is received within duration seconds, the profile expires.

9. Q06 — External V2X Control with Charging Profile from External System

External
Use Case ID Q06
Objective An External System (e.g. EMS) directly controls charging limits or setpoints via a ChargingStationExternalConstraints profile

CSMS Role

The CSMS does not directly send the charging profile in this flow. Instead, the External System sends it directly to the Charging Station. However, the CSMS:

  1. Receives NotifyChargingLimitRequest messages from the Charging Station informing it of the external limits.
  2. May need to manage priority via SmartChargingCtrlr.SetpointPriority.

Handle NotifyChargingLimitRequest (CS → CSMS)

Incoming NotifyChargingLimitRequest
{
  "chargingLimit": {
    "chargingLimitSource": "EMS",
    "isGridCritical": false
  },
  "evseId": 0,
  "chargingSchedule": [{
    "id": 1,
    "chargingRateUnit": "W",
    "chargingSchedulePeriod": [{
      "startPeriod": 0,
      "operationMode": "ExternalLimits",
      "limit": 15000,
      "dischargeLimit": -10000
    }]
  }]
}
NotifyChargingLimitResponse
{}

Empty response body — no required fields.

Setpoint Priority (Q06.FR.20-22)

When both a ChargingStationExternalConstraints profile with ExternalSetpoint AND a TxProfile/TxDefaultProfile also define a setpoint, the variable SmartChargingCtrlr.SetpointPriority determines which takes precedence:

Priority Value Behavior
"ExternalControl" (or absent) Use setpoint from ChargingStationExternalConstraints profile
"CSMS" Use setpoint from TxProfile or TxDefaultProfile, overruling external

10. Q07 — Central V2X Control for Frequency Support

CSMS-Initiated
Use Case ID Q07
Objective CSMS controls the power setpoint for frequency support, updating it dynamically based on centrally measured frequency
Prerequisites CS reports CentralFrequency in V2XSupportedOperationModes

Step 1: Send SetChargingProfileRequest

SetChargingProfileRequest — CentralFrequency
{
  "evseId": 1,
  "chargingProfile": {
    "id": 500,
    "stackLevel": 2,
    "chargingProfilePurpose": "TxProfile",
    "chargingProfileKind": "Dynamic",
    "transactionId": "tx-abc-123",
    "chargingSchedule": [{
      "id": 1,
      "chargingRateUnit": "W",
      "duration": 60,
      "chargingSchedulePeriod": [{
        "startPeriod": 0,
        "operationMode": "CentralFrequency",
        "setpoint": 0
      }]
    }]
  }
}

Requirement Q07.FR.02: CSMS SHALL send a profile with chargingProfileKind = Dynamic and operationMode = CentralFrequency.

Requirement Q07.FR.03: CSMS SHALL NOT include limit and dischargeLimit (including L2/L3 variants).

Requirement Q07.FR.04: CSMS IS RECOMMENDED to set a duration to prevent indefinite operation if CSMS becomes unavailable.

Step 2: Periodically Update Setpoint

Use UpdateDynamicScheduleRequest to push frequency-based setpoint changes:

UpdateDynamicScheduleRequest — Frequency Setpoint
{
  "chargingProfileId": 500,
  "scheduleUpdate": {
    "setpoint": -3000
  }
}

Fallback Behavior: If no UpdateDynamicScheduleRequest is received before duration expires, the profile terminates. If the CS supports LocalFrequency, it can fall back to a lower-stack-level profile with LocalFrequency mode.

11. Q08 — Local V2X Control for Frequency Support

CSMS-Initiated
Use Case ID Q08
Objective CSMS provides frequency-watt curves and the Charging Station autonomously adjusts power based on local frequency measurements

Scenario 1: FCR (Frequency Containment Reserve)

SetChargingProfileRequest — LocalFrequency FCR
{
  "evseId": 1,
  "chargingProfile": {
    "id": 600,
    "stackLevel": 2,
    "chargingProfilePurpose": "TxProfile",
    "chargingProfileKind": "Absolute",
    "transactionId": "tx-abc-123",
    "chargingSchedule": [{
      "id": 1,
      "chargingRateUnit": "W",
      "chargingSchedulePeriod": [{
        "startPeriod": 0,
        "operationMode": "LocalFrequency",
        "v2xBaseline": 0,
        "v2xFreqWattCurve": [
          { "frequency": 47.0,   "power": -10000 },
          { "frequency": 49.80,  "power": -10000 },
          { "frequency": 49.99,  "power": -500 },
          { "frequency": 49.991, "power": 0 },
          { "frequency": 50.0,   "power": 0 },
          { "frequency": 50.009, "power": 0 },
          { "frequency": 50.01,  "power": 500 },
          { "frequency": 50.20,  "power": 10000 },
          { "frequency": 53.0,   "power": 10000 }
        ]
      }]
    }]
  }
}

Scenario 2: FCR + aFRR (Automatic Frequency Restoration Reserve)

Add v2xSignalWattCurve for aFRR:

ChargingSchedulePeriod — LocalFrequency with FCR + aFRR
{
  "startPeriod": 0,
  "operationMode": "LocalFrequency",
  "v2xBaseline": 0,
  "v2xFreqWattCurve": [
    { "frequency": 47.0,  "power": -10000 },
    { "frequency": 49.80, "power": -10000 },
    { "frequency": 49.99, "power": -500 },
    { "frequency": 50.0,  "power": 0 },
    { "frequency": 50.01, "power": 500 },
    { "frequency": 50.20, "power": 10000 },
    { "frequency": 53.0,  "power": 10000 }
  ],
  "v2xSignalWattCurve": [
    { "signal": -1, "power": -2000 },
    { "signal": 0,  "power": 0 },
    { "signal": 1,  "power": 2000 }
  ]
}

Validation Rules

The CS will reject the profile with SetChargingProfileResponse.status = Rejected if:

Condition reasonCode
v2xFreqWattCurve missing or has < 2 points, or v2xBaseline missing "NoFreqWattCurve"
Contains limit, dischargeLimit, setpoint, or setpointReactive "InvalidSchedule"

Requirement Q08.FR.05: The chargingRateUnit MUST be W for LocalFrequency schedules.

Setpoint Calculation (done by CS)

setpoint = v2xBaseline + interpolate(v2xFreqWattCurve, measuredFrequency) + interpolate(v2xSignalWattCurve, signal)

Send AFRRSignalRequest for aFRR (CSMS → CS)

When the CSMS receives an aFRR signal from a TSO:

AFRRSignalRequest
{
  "timestamp": "2026-02-17T14:30:00Z",
  "signal": 1
}
AFRRSignalRequest Schema
{
  "timestamp": string (date-time, required)    // Time when signal becomes active
  "signal": integer (required)                 // Value mapped to v2xSignalWattCurve
}
AFRRSignalResponse — Accepted
{
  "status": "Accepted"
}
AFRRSignalResponse — Rejected
{
  "status": "Rejected",
  "statusInfo": {
    "reasonCode": "NoSignalWattCurve"
  }
}

Requirement Q08.FR.12: When CSMS receives an aFRR signal from external actor (TSO), CSMS SHALL send AFRRSignalRequest with timestamp = current time and signal = value from external actor.

12. Q09 — Local V2X Control for Load Balancing

CSMS-Initiated
Use Case ID Q09
Objective CSMS provides a LocalLoadBalancing schedule and the Charging Station autonomously adjusts power based on local grid meter readings

CSMS Action: Send SetChargingProfileRequest

SetChargingProfileRequest — LocalLoadBalancing
{
  "evseId": 1,
  "chargingProfile": {
    "id": 700,
    "stackLevel": 2,
    "chargingProfilePurpose": "TxProfile",
    "chargingProfileKind": "Absolute",
    "transactionId": "tx-abc-123",
    "chargingSchedule": [{
      "id": 1,
      "chargingRateUnit": "W",
      "chargingSchedulePeriod": [{
        "startPeriod": 0,
        "operationMode": "LocalLoadBalancing"
      }]
    }]
  }
}

Rejection Conditions

Condition reasonCode
LocalLoadBalancing not in V2XSupportedOperationModes "UnsupportedParam"
Required thresholds not configured "MissingDevModelInfo"

Configuration Variables (set via SetVariablesRequest)

These must be configured on the Charging Station before using LocalLoadBalancing:

Variable Description
V2XLocalLoadBalancing[UpperThreshold] Load above this triggers discharge
V2XLocalLoadBalancing[LowerThreshold] Load below this triggers charge
V2XLocalLoadBalancing[UpperOffset] Overshoot above upper threshold
V2XLocalLoadBalancing[LowerOffset] Overshoot below lower threshold

Setpoint Algorithm (executed by CS)

Load Balancing Algorithm
Load = get latest load power reading()

If Load > UpperThreshold:
    DeltaSetpoint = UpperThreshold + UpperOffset - Load
Else If Load < LowerThreshold:
    DeltaSetpoint = LowerThreshold + LowerOffset - Load
Else:
    DeltaSetpoint = 0

setpoint = setpoint + DeltaSetpoint

Setpoint is capped by limit (positive) and dischargeLimit (negative) when set.

13. Q10 — Idle, Minimizing Energy Consumption

CSMS-Initiated
Use Case ID Q10
Objective Request the EV to stop all charging/discharging and optionally precondition or sleep

Scenario 1: Idle with Preconditioning

SetChargingProfileRequest — Idle with Preconditioning
{
  "evseId": 1,
  "chargingProfile": {
    "id": 800,
    "stackLevel": 2,
    "chargingProfilePurpose": "TxProfile",
    "chargingProfileKind": "Absolute",
    "transactionId": "tx-abc-123",
    "chargingSchedule": [{
      "id": 1,
      "chargingRateUnit": "W",
      "chargingSchedulePeriod": [{
        "startPeriod": 0,
        "operationMode": "Idle",
        "preconditioningRequest": true
      }]
    }]
  }
}

Scenario 2: Idle without Preconditioning

ChargingSchedulePeriod — Idle (no preconditioning)
{
  "startPeriod": 0,
  "operationMode": "Idle",
  "preconditioningRequest": false
}

Scenario 3: EVSE Sleep

ChargingSchedulePeriod — EVSE Sleep
{
  "startPeriod": 0,
  "operationMode": "Idle",
  "evseSleep": true
}

When evseSleep = true, the CS turns off power electronics. The CS reports evseSleep = true in subsequent TransactionEventRequest messages.

Requirement Q10.FR.01: In Idle mode, limit, dischargeLimit, setpoint, and setpointReactive (including L2/L3) SHALL be absent.

Requirement Q10.FR.02: CS will reject profiles that include those fields with reasonCode = "InvalidSchedule".

14. Q11 — Going Offline During V2X Operation

CSMS-Initiated
Use Case ID Q11
Objective Define how long V2X operations continue when the Charging Station loses connection to CSMS

CSMS Action: Set maxOfflineDuration on Charging Profiles

SetChargingProfileRequest — With Offline Duration
{
  "evseId": 1,
  "chargingProfile": {
    "id": 900,
    "stackLevel": 2,
    "chargingProfilePurpose": "TxProfile",
    "chargingProfileKind": "Absolute",
    "transactionId": "tx-abc-123",
    "maxOfflineDuration": 300,
    "invalidAfterOfflineDuration": false,
    "chargingSchedule": [{
      "id": 1,
      "chargingRateUnit": "W",
      "chargingSchedulePeriod": [{
        "startPeriod": 0,
        "operationMode": "CentralSetpoint",
        "setpoint": 5000,
        "limit": 11000,
        "dischargeLimit": -5000
      }]
    }]
  }
}

Key Fields

Field Type Description
maxOfflineDuration integer (seconds) Time the profile stays valid after going offline. 0 = immediately invalid. Absent = no timeout.
invalidAfterOfflineDuration boolean If true, profile is permanently invalidated after timeout. If false (default), profile reactivates when connection is restored.

Behavior

  1. CS detects it is offline.
  2. maxOfflineDuration countdown starts.
  3. After maxOfflineDuration seconds, CS falls back to the next valid profile with a lower stack level.
  4. CSMS should assume V2X has reverted when it detects the CS is offline.

Recommended Stack Level Strategy

Send two profiles:

  1. Stack level 1: ChargingOnly (safe fallback)
  2. Stack level 2: V2X operation (e.g. CentralSetpoint) with maxOfflineDuration

15. Q12 — Resuming V2X After Offline Period

CSMS-Initiated
Use Case ID Q12
Objective Resume V2X operations after the Charging Station reconnects

Scenarios

Scenario 1: maxOfflineDuration NOT elapsed

The V2X profile remained active. No CSMS action needed. CS continues with the same profile.

Scenario 2: maxOfflineDuration elapsed, invalidAfterOfflineDuration = false

  1. CS reconnects.
  2. CS re-evaluates profiles and selects the V2X profile (stack level 2) again.
  3. V2X resumes automatically.
  4. CSMS can send a new SetChargingProfileRequest if needed.

Scenario 3: maxOfflineDuration elapsed, invalidAfterOfflineDuration = true

  1. CS reconnects.
  2. The V2X profile is permanently invalid.
  3. CS continues using the fallback profile (stack level 1, ChargingOnly).
  4. CSMS must send a new SetChargingProfileRequest to re-establish V2X.

CSMS Implementation

CSMS Reconnection Logic
on_connection_restored(charging_station):
    if invalidAfterOfflineDuration was true:
        // Must send a new V2X profile
        send_new_v2x_charging_profile(charging_station)
    else:
        // Profile may have auto-restored, verify via GetCompositeSchedule
        verify_active_profile(charging_station)

16. Generic V2X Smart Charging Rules

Reference

These rules apply across ALL V2X use cases:

Rule ID Description
V2X.01 All requirements from section K (Smart Charging) also apply to V2X.
V2X.02 A setpoint (or setpointReactive) is a target value; a limit is a maximum value.
V2X.03 CS SHALL cap positive setpoint to limit value (e.g. setpoint=2000, limit=1000 → sent to EV: 1000).
V2X.04 CS SHALL cap negative setpoint to dischargeLimit (e.g. setpoint=-2000, dischargeLimit=-1000 → sent to EV: -1000). Does NOT apply to setpointReactive. When chargingRateUnit = A, limit is about current.
V2X.05 CS SHALL reject SetChargingProfileRequest with Rejected + reasonCode="InvalidSchedule" if setpoint is outside the range [dischargeLimit, limit]. E.g. reject if setpoint=-750 when limit=1000 and dischargeLimit=-500.
V2X.06 Requirements for limit, dischargeLimit, setpoint, setpointReactive also apply to _L2 and _L3 variants.
V2X.07 L2/L3 variants can only occur in combination with the base field (without postfix).
V2X.08 CSMS SHALL NOT provide L2/L3 values for dischargeLimit, setpoint(Reactive) if the EV didn't report maxDischargePower_L2/_L3 in NotifyEVChargingNeedsRequest.
V2X.09 CSMS SHALL NOT provide L2/L3 discharge/setpoint fields for profiles other than TxProfile.
V2X.10 If V2X.08 or V2X.09 is violated and CS receives L2/L3 fields, CS SHALL reject with status=Rejected, reasonCode="PhaseConflict".

17. Configuration Variables Reference

Reference
Variable Description
ISO15118Ctrlr.Enabled Must be true for V2X
V2XChargingCtrlr.Enabled Must be true for V2X
V2XChargingCtrlr.V2XSupportedOperationModes List of supported operation modes
V2XChargingCtrlr.SupportedEnergyTransferModes List of supported energy transfer modes
V2XChargingCtrlr.TxStartedMeasurands Measurands to include at transaction start per operation mode
V2XChargingCtrlr.TxEndedMeasurands Measurands to include at transaction end per operation mode
V2XChargingCtrlr.TxUpdatedMeasurands Measurands to include in periodic updates per operation mode
V2XChargingCtrlr.LocalFrequencyUpdateThreshold Min frequency change (mHz) to trigger recalculation
V2XLocalLoadBalancing[UpperThreshold] Load threshold to start discharging
V2XLocalLoadBalancing[LowerThreshold] Load threshold to start charging
V2XLocalLoadBalancing[UpperOffset] Overshoot above upper threshold
V2XLocalLoadBalancing[LowerOffset] Overshoot below lower threshold
ExternalControlSignalsEnabled Must be true for Q05
ExternalConstraintsProfileDisallowed When true, blocks external system from setting profiles directly (Q05). When false or absent, allows external profiles (Q06).
SmartChargingCtrlr.SetpointPriority "ExternalControl" or "CSMS" — determines priority between external and CSMS setpoints
SmartChargingCtrlr.SupportsEvseSleep Whether EVSE supports sleep mode
SmartChargingCtrlr.LimitChangeSignificance Threshold for reporting limit changes
ConnectedEV.VehicleId EVCCID of connected EV
ConnectedEV.VehicleCertificate Vehicle certificate
ConnectedEV.Available Whether EV is connected
ConnectedEV.ProtocolAgreed Agreed protocol
ConnectedEV.ProtocolSupportedByEV Protocols supported by EV

18. Message Direction Summary

Reference
Message Direction CSMS Role
AuthorizeRequest CS → CSMS Respond with allowedEnergyTransfer
AuthorizeResponse CSMS → CS Include allowedEnergyTransfer array
TransactionEventRequest CS → CSMS Handle V2X fields (operationMode, evseSleep)
TransactionEventResponse CSMS → CS Standard response
NotifyEVChargingNeedsRequest CS → CSMS Respond with accept/reject, then send profile
NotifyEVChargingNeedsResponse CSMS → CS Accepted/Processing/NoChargingProfile/Rejected
SetChargingProfileRequest CSMS → CS Send V2X charging profiles
SetChargingProfileResponse CS → CSMS Accepted/Rejected with reason
UpdateDynamicScheduleRequest CSMS → CS Send dynamic setpoint updates
UpdateDynamicScheduleResponse CS → CSMS Accepted/Rejected
PullDynamicScheduleUpdateRequest CS → CSMS Respond with updated schedule parameters
PullDynamicScheduleUpdateResponse CSMS → CS Include scheduleUpdate with new values
AFRRSignalRequest CSMS → CS Send aFRR signal for frequency support
AFRRSignalResponse CS → CSMS Accepted/Rejected
NotifyAllowedEnergyTransferRequest CSMS → CS Send updated allowed energy transfer list
NotifyAllowedEnergyTransferResponse CS → CSMS Accepted/Rejected
NotifyChargingLimitRequest CS → CSMS Handle external limit notifications
NotifyChargingLimitResponse CSMS → CS Empty response
NotifyEVChargingScheduleRequest CS → CSMS Handle EV-selected schedule notifications
NotifyEVChargingScheduleResponse CSMS → CS Accepted/Rejected

Quick Decision Tree for CSMS

CSMS V2X Decision Flow
EV plugs in
  |
  v
AuthorizeRequest received
  |
  +--> Can determine V2X permission now?
  |     YES --> Include allowedEnergyTransfer in AuthorizeResponse
  |     NO  --> Omit allowedEnergyTransfer (flow Q02)
  |
  v
TransactionEventRequest (Started) received
  |
  v
NotifyEVChargingNeedsRequest received
  |
  +--> Is requestedEnergyTransfer a BPT mode?
  |     YES --> Accept, send V2X profile (Q01/Q03/Q04/Q07/Q08/Q09)
  |     NO  --> Accept, send ChargingOnly profile (Q02)
  |
  +--> Is requestedEnergyTransfer rejected?
        YES --> Respond with status=Rejected
  |
  v
Choose V2X operation mode:
  |
  +--> CSMS controls setpoint with schedule? ---------> Q03 (CentralSetpoint, Absolute)
  +--> CSMS controls setpoint dynamically? -----------> Q04 (CentralSetpoint, Dynamic)
  +--> External system controls via CSMS profile? ----> Q05 (ExternalSetpoint/ExternalLimits)
  +--> External system controls directly? ------------> Q06 (ChargingStationExternalConstraints)
  +--> CSMS controls frequency support? --------------> Q07 (CentralFrequency)
  +--> Local frequency support with curves? ----------> Q08 (LocalFrequency)
  +--> Local load balancing? -------------------------> Q09 (LocalLoadBalancing)
  +--> Pause/idle EV? -------------------------------> Q10 (Idle)

OCPP 2.1 Bidirectional Power Transfer (V2X) Flows (Q01–Q12) - CSMS Developer Guide. Based on OCPP 2.1 Edition 2 Specification (Part 2), Section Q.