OCPP Charge Point

For EVSE devices the DER Simulator connects to a Charging Station Management System (CSMS) over OCPP as a charge point. All three mainline OCPP versions are supported:

OCPP version
1.6j
2.0.1j
2.1

Pick the version with the --ocpp_version flag; the rest of the wire behavior follows automatically.

Starting an EVSE in OCPP mode

./sim --evse_profile EVSE-DC-150kW-CCS-1port.json \
      --ocpp_enable yes \
      --ocpp_version ocpp2.1 \
      --ocpp_csms_url wss://csms.example.com/ocpp \
      --ocpp_csid DERSIM-LAB-1
Flag Default Description
--ocpp_enable no Start the OCPP charge-point client alongside the rest of the simulator
--ocpp_version ocpp1.6j One of ocpp1.6j, ocpp2.0.1j, ocpp2.1
--ocpp_csms_url (none) WebSocket URL of the CSMS
--ocpp_csid DERSIM-CP-1 Charge-point identifier the CSMS registers
--evse_profile (built-in 22-kW AC) Path to a JSON EVSE profile

The --evse_profile flag is the canonical way to load an EVSE topology. The SunSpec -f flag rejects EVSE profiles with a clear error pointing at this flag.

See EVSE Profiles for the six bundled profiles (single-AC, dual-AC, DC fast-charger, dual DC ultra-fast, hybrid, V2G) with copy-paste command lines.

Transaction lifecycle

The simulator drives a complete transaction lifecycle automatically once the CSMS authorizes the session:

  1. BootNotification on connect; gates further CP-initiated calls on Accepted.
  2. StatusNotification(Available) for each connector.
  3. Authorize(idToken) on simulated cable-plug.
  4. TransactionEvent(Started) once authorized.
  5. MeterValues at the configured cadence, plus TransactionEvent(Updated) for each state transition (charging → suspended-EV → charging).
  6. TransactionEvent(Ended, reason=...) on simulated unplug or remote stop.
  7. StatusNotification(Available).

Heartbeat fires at the interval the CSMS returned in its BootNotificationResponse.

V2G (Vehicle-to-Grid) discharge

V2G-capable EVSE profiles advertise bidirectional energy-transfer modes (AC_BPT, DC_BPT) to the CSMS. During a discharge transaction:

  • MeterValues includes Power.Active.Export instead of Import.
  • TransactionEvent carries the right chargingState transitions (chargingev_connectedcharging-but-exporting).
  • OCPP 2.1: NotifyAllowedEnergyTransfer fires mid-transaction when the EV completes ISO 15118-20 capability advertisement and is found to support bidirectional DC.

OCPP 2.1 — DER Control

OCPP 2.1's headline feature is a unified SetDERControl envelope that addresses every IEEE 1547-2018 grid-support mode (Volt-Var, Volt-Watt, Watt-Var, fixed PF, watt-limit, gradients, enter-service) on a single message. The simulator reuses the same DER behavior it exposes over IEEE 2030.5 / CSIP, so an OCPP 2.1 CSMS gets results indistinguishable from a 2030.5 server driving the same DER.

Supported controlType values

controlType Behavior
VoltVar Volt-Var curve (reactive power vs. voltage)
VoltWatt Volt-Watt curve (active-power curtailment vs. voltage)
WattVar Watt-Var curve (reactive power vs. active power)
FixedPFInject Fixed power factor while injecting
FixedPFAbsorb Fixed power factor while absorbing
FixedVar Fixed reactive-power setpoint
LimitMaxDischarge Active-power discharge ceiling
Gradients Ramp-rate setpoint
EnterService Enter-service voltage / frequency envelope

Trip controls (HVMustTrip, LVMustTrip, HFMustTrip, LFMustTrip, HVMomCess, LVMomCess, etc.) return NotSupported today.

Supersession stack

When multiple SetDERControl calls arrive for the same (controlType, isDefault) group, the simulator tracks them in a priority-ordered stack:

  • The entry with the lowest numeric priority is active and drives the inverter. The rest are superseded and reported as is_superseded=true in ReportDERControl.
  • NotifyDERStartStop(started=true) carries the displaced peers' IDs in the superseded_ids field so the CSMS sees the displacement explicitly.
  • Clearing the active entry promotes the next-priority peer in the same group so the inverter picks up its parameters seamlessly.
  • Re-asserting an existing controlId with a worse priority can demote it; the simulator recomputes against the whole group, not just the previously-active entry.

NotifyDERAlarm on inverter trip

While at least one DER control is active, the simulator watches the inverter's trip state at 1 Hz. On a clean → tripped transition it emits NotifyDERAlarm(alarm_ended=false) with the matching GridEventFault cause (UnderVoltage, OverVoltage, UnderFrequency, OverFrequency). On the clear it emits alarm_ended=true. One alarm fires per active controlType group; multiple superseded entries in the same group share the same alarm.

Multi-page ReportDERControl

GetDERControl is answered with Accepted, followed by one or more ReportDERControl calls. The simulator paginates the result set into chunks of 10 entries by default; every page except the last carries tbc=true, the final page carries tbc=false. An empty result set still emits one terminal tbc=false page so the Accepted request is closed out rather than dangling.

ClearDERControl restore-to-default

When the last active overlay (isDefault=false) for a controlType is cleared, the simulator re-applies the matching default (isDefault=true) so the inverter reverts to its baseline IEEE-1547 behavior rather than holding the just-cleared overlay's setpoints. Within-group supersession promotion still takes precedence — when a same-group peer is queued, that peer is promoted and the default is not re-invoked.

OCPP log module

Every OCPP CALL / CALLRESULT / CALLERROR frame is mirrored into the simulator's log buffer under a dedicated OCPP module tag. Filter the dashboard's Logs view by the OCPP module to see the live wire conversation between the simulator and your CSMS — BootNotification, StatusNotification, Authorize, TransactionEvent, SetDERControl, NotifyDERStartStop, NotifyDERAlarm, ReportDERControl, the full set — alongside the simulator's own log lines (boot handshake, DER control accept/reject, trip detection, etc.).

Sensitive fields are redacted before the log line reaches the buffer:

  • idToken, idTag — authorization tokens (cardholder PII)
  • certificate, certificateChain, csr, hash — PKI material
  • password — basic-auth credentials
  • customerInformation, vin — customer / vehicle identifiers

The value reads <redacted> while the field name stays visible so a viewer can still tell the frame carried the field. Heartbeat frames are dropped before reaching the buffer — they fire every ~60 s in steady state and carry no observability value.

Multi-port stations

EVSE profiles can declare more than one port (e.g. a dual-cabinet DC fast charger). Each port runs its own connector state machine and transaction lifecycle independently; the inverter / battery shared across ports allocates available power proportionally to per-port demand. MeterValues report the allocated-not-requested kW per port, so an aggregator-side load-balancing test exercising contention sees realistic per-port telemetry.

CLI flag reference (full)

Beyond the four commonly-used flags above, the OCPP charge-point client honors these:

Flag Default Description
--ocpp_evse_id 1 Which EVSE entry (from the loaded profile) the OCPP client binds to
--ocpp_basic_auth_user (charge_point_id) HTTP Basic-auth username for the CSMS connection
--ocpp_basic_auth_password (none) HTTP Basic-auth password for the CSMS connection (Security Profile 1)
--ocpp_cert (none) Client certificate PEM for mTLS (Security Profile 2/3); requires --ocpp_key
--ocpp_key (none) Client private-key PEM for mTLS; requires --ocpp_cert
--ocpp_root_cert (system store) CA bundle PEM used to verify the CSMS server certificate (wss:// only)
--ocpp_skip_verify no Disable server-cert + hostname verification (staging / self-signed only — never production)
--ocpp_ciphers (library default) OpenSSL cipher list override
--ocpp_cert_store_dir (in-memory) Directory to persist the OCPP §A2 keypair so cert rotation survives restarts

Setting up a CSMS

The DER Simulator does not distribute a CSMS — pick one from the ecosystem. Two well-known free/open-source options are:

SteVe (OCPP 1.6j)

Java-based, MariaDB-backed CSMS from RWTH Aachen.

  • Source: steve-community/steve
  • Run with Docker: the upstream repo ships a docker-compose.yml — clone, then docker compose up -d. SteVe builds the WAR from source on first run; expect ~5–10 min cold, ~30–60 s warm.
  • Default URLs:
  • Point the simulator at the WS URL with --ocpp_csms_url and --ocpp_version ocpp1.6j.

CitrineOS (OCPP 2.0.1 + 2.1)

TypeScript-based, Postgres + RabbitMQ-backed CSMS sponsored by the Open Charge Alliance — the reference 2.1 implementation.

  • Source: citrineos/citrineos-core
  • Run with Docker: clone, then docker compose up -d in the Server/ directory.
  • Default URLs:
    • Operator web UI: http://localhost:8080/
    • OCPP 2.0.1 / 2.1 WebSocket: ws://localhost:8081/ocpp/<charge_point_id>
  • Point the simulator at the WS URL with --ocpp_csms_url and --ocpp_version ocpp2.0.1j or ocpp2.1.

Both CSMSes expect to receive a BootNotification from any charging station id they don't already know about; check the per-CSMS configuration if BootNotification is being rejected (SteVe ships the auto-register-unknown-stations switch; CitrineOS auto-creates on first contact in its default config).

Web UI — EVSE page

When the simulator is launched with --ocpp_enable=yes, the dashboard's sidebar gains an EVSE / OCPP entry. The page surfaces per-port state for every EVSE the runtime knows about:

Column Meaning
State IEC 61851-1 state (A / B1 / B2 / C / D / E / F)
OCPP 1.6 Mapped 1.6 ChargePointStatus (Available / Preparing / Charging / …)
OCPP 2.x Mapped 2.0.1+ ConnectorStatusEnumType
Max kW Per-port hard rating from the EVSE profile
Requested What the car's curve currently wants
Allocated What the multi-port arbiter actually grants (with throttled chip if reduced)
Vehicle Plugged-in vehicle model + SoC %
Transaction Active OCPP transaction id + delivered kWh, or

Per-port action buttons:

  • Plug in — opens the vehicle picker (see below) and presents the chosen car to the connector. State transitions A → B2.
  • Start — drives a local transaction start (mints idToken, fires Authorize, then TransactionEvent(Started)). Visible once a vehicle is plugged in.
  • Stop — ends the active transaction with Reason=Local.
  • Unplug — removes the vehicle, state returns to A.

Vehicle picker

Picking which car to plug in is a searchable modal over the 50-vehicle catalog bundled with the simulator (Class 1 light-duty through Class 8 heavy-duty trucks). The modal supports:

  • Free-text search by manufacturer, model, model id, or class.
  • V2G capable only checkbox to filter to bidirectional-capable vehicles for V2G testing.
  • Class dropdown to narrow to a specific vehicle class (1–8 / MD / HD).
  • Per-vehicle chips showing class, battery capacity (kWh), max AC kW, max DC kW, and a green V2G chip when applicable.

Press Enter on a filtered list to pick the first match; double-click or click Plug in to confirm.

Web UI — OCPP Settings page

The OCPP Settings sidebar entry (visible alongside the EVSE / OCPP page when an EVSE is registered) is where an operator twiddles the live OCPP charge point without needing the CSMS. The page is split into three cards:

Authorization

Top section. Three toggles map to the OCPP device-model variables under AuthCtrlr:

  • LocalPreAuthorize — when on, the CP authorises an idToken locally from its cache if a fresh Accepted entry exists; only falls through to the CSMS on a cache miss. Saves a round-trip on every plug-in for known cardholders.
  • LocalAuthorizeOffline — when on and the wire call to the CSMS fails (drop, timeout), the CP falls back to its cache rather than rejecting the cardholder outright.
  • AuthorizeRemoteStart — when on, the CP requires an explicit Authorize for RemoteStart transactions; when off, the CSMS's RequestStartTransaction is treated as authoritative.

Below the toggles, the Authorization cache table lists every cached idToken with its status, optional cache_expiry_date_time, charging priority, and group token. Each row has a drop button for surgical removal; Clear all wipes the whole cache.

TLS / Security Profile

The Security Profile card shows the persisted state of the Charging Station Certificate keypair (OCPP §A2):

  • Store dir — where the keypair lives on disk (set via --ocpp_cert_store_dir).
  • Keypresent (with path + SHA prefix) or missing.
  • CSR — last CSR sent to the CSMS, with SHA prefix.
  • Signed cert — the chain the CSMS returned, with SHA prefix.

The Rotate certificate button kicks off a fresh OCPP §A2 cycle: the CP mints a new RSA keypair, persists it, ships the CSR via SignCertificate, and waits for CertificateSigned. When the signed chain comes back, the bridge automatically tears down the WebSocket and re-handshakes mTLS with the new client cert. No operator action needed beyond the button press.

When --ocpp_cert_store_dir is not set, the cert chain lives in memory only and the Rotate button is disabled. The card surfaces the disabled state so the operator knows what to fix.

Device model

The bottom card lists every variable the OCPP 2.0.1 device model exposes. For each row:

  • Component / variable name
  • Value — editable inline if the variable is on the editable list (e.g. HeartbeatInterval, TxUpdatedInterval, AuthCtrlr toggles); CSMS-only otherwise
  • FlagsRO (read-only), reboot (change takes effect after a reboot)

Edit and tab/blur to push the change; the new value is applied immediately to the live device model. The same surface backs the CSMS's GetVariables / SetVariables calls — what the operator sees here is what the CSMS sees.

OCPP wire log

Filter the dashboard's Logs view by module OCPP to see every CALL / CALLRESULT / CALLERROR frame the CP and CSMS exchange. Useful for end-to-end troubleshooting; covered earlier under OCPP log module.