ISO 15118-20 Operator Runbook
ISO 15118-20 is the second-generation high-level communication protocol for CCS. ChargeLink implements the SupportedAppProtocol, CommonMessages and DC namespaces with a native EXI codec, and runs the full DC EIM session (16 request/response pairs from SupportedAppProtocol to SessionStop) between two machines, with the ChargeLink SECC on one PC and the ChargeLink EVCC on a second PC.
Before you start
- TLS 1.3 with mutual authentication is mandatory. The listener rejects plaintext, TLS 1.2 and connections without a verified client certificate before the SupportedAppProtocol exchange, and it negotiates only the named groups secp521r1 and x448 and the cipher suites TLS_AES_256_GCM_SHA384 and TLS_CHACHA20_POLY1305_SHA256 (see TLS, PKI and Plug & Charge). You need a V2G root CA, a SECC certificate chain and key for the EVSE, and a vehicle certificate chain and key for the EVCC, all under the same root. Engineering material can be generated with
evse tls-material-init(a fresh Annex B-shaped chain on every run, accepted byevse startonly with--allow-engineering-tls-identity); production material must follow ISO 15118-20 Annex B (ECDSA P-521, SHA-512). See TLS, PKI and Plug & Charge. - TLS named groups. The handshake offers and accepts only secp521r1 and x448, so a peer that offers only other groups (for example P-256 or X25519) is refused before any V2G message.
--allow-legacy-tls-named-groupsadds secp256r1 after them for engineering interop with such peers. - The EVSE identity in the certificate is validated as an Annex B chain to the V2G root. The DNS name is SNI only; the EVCC default
--tls-server-name chargelink-secc.localdoes not need to match a SAN. - Complete the preflight: interface index, link-local address, ports, clock.
$CL = 'C:\ChargeLink\0.5.0-rc2\pc1\bin\chargelink.exe'
$Data = 'C:\ChargeLinkData'
$IfIndex = <INTERFACE_INDEX>
$Advertise = 'fe80::<ADDRESS>%' + $IfIndex
$Pki = "$Data\pki"
1. Choose a profile
| Profile ID | Role | Mode | Lane |
|---|---|---|---|
iso15118_20_dc | EVSE | DC EIM | Reference responder; with --plant-grpc-endpoint the plant-coupled runtime lane |
abb_iso20_dc_bpt_eim | EVSE | DC BPT EIM | Reference responder (BPT service discovery/detail vectors) |
abb_iso20_ac_eim_realistic_continuous | EVSE | AC EIM | Reference responder (AC vectors) |
abb_iso20_ac_bpt_eim | EVSE | AC BPT EIM | Reference responder |
abb_iso20_dc_pnc_tls, abb_iso20_ac_pnc_tls, abb_iso20_dc_bpt_pnc_tls, abb_iso20_ac_bpt_pnc_tls | EVSE | PnC | Reference responder; PnC is advertised only when a PnC fixture manifest is configured (see TLS page) |
iso15118_20_dc_evcc_reference | EVCC | DC EIM | Live session (EV case files from the package required) |
iso15118_20_ac_evcc_reference, *_bpt_*, *_pnc_*, iso15118_20_dc_evcc_premium_800v, iso15118_20_dc_evcc_cold_demo | EVCC | various | Dry-run, loopback and deterministic simulation only |
AC, DC and BPT are selected from the profile ID tokens (ac, dc, bpt). The installed profile list is authoritative.
The DC EIM session at a glance
2. EVSE: reference-responder session for an external EVCC
Use this lane to validate a vehicle or EVCC simulator against ChargeLink discovery, TLS 1.3, V2GTP framing and message sequencing. Every request is decoded and answered with the validated reference response for that message.
$Run = "iso20-dc-$(Get-Date -Format yyyyMMdd-HHmmss)"
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse live-preflight --source external-evcc `
--protocol iso15118-20 --profile-id iso15118_20_dc `
--host '::' --tcp-port 50118 --udp-port 15118 `
--advertise-ipv6 $Advertise --interface-index $IfIndex `
--tls --tls-cert "$Pki\secc-chain.pem" --tls-key "$Pki\secc-key.pem" --tls-cafile "$Pki\v2g-root-ca.pem" --require-ca `
--recover-stale
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse start --external-evcc-session --run-id $Run `
--protocol iso15118-20 --profile-id iso15118_20_dc `
--host '::' --tcp-port 50118 --udp-port 15118 `
--advertise-ipv6 $Advertise --interface-index $IfIndex `
--tls --tls-cert "$Pki\secc-chain.pem" --tls-key "$Pki\secc-key.pem" --tls-cafile "$Pki\v2g-root-ca.pem" --require-ca `
--max-runtime-ms 1800000 --heartbeat-interval-ms 1000
Notes:
--external-evcc-sessionkeeps the listener open until--max-runtime-mselapses or an operator stop arrives, and defaults UDP to 15118.--tcp-port 0auto-allocates a port from 49152–65535; the bound port is reported in the JSON result and inevse_listener_status.json.- Do not use
--external-evcc-windows-tlsor--external-evcc-dev-tlsfor ISO 15118-20: both select TLS 1.2, which the ISO 15118-20 admission check rejects. - The response budget is enforced: ChargeLoop 250 ms, ServiceDetail 4500 ms, other messages 1500 ms, CableCheck 38 s. Exceeding a budget is recorded as a finding.
In a second window:
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse status --run-id $Run
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse list-state --run-id $Run
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json runtime inspect --run-id $Run
3. EVSE: plant-coupled runtime session (DC EIM)
This is the lane in which ChargeLink encodes every ISO 15118-20 response from the live session state and from plant measurements, and drives PreCharge, PowerDelivery and the DC charge loop against the vehicle's targets. It requires:
- profile
iso15118_20_dc, TLS 1.3 mutual (--require-ca); --plant-grpc-endpoint: the ChargeLink gRPC endpoint to which the plant provider (the VeriStand owner host) is bound;- explicit
--requested-power-kwand--target-voltage-v(zero means unset and is rejected); - the environment variable
CHARGELINK_ISO20_RUNTIME_PROFILEpointing to a runtime profile JSON (schemachargelink.iso15118_20.dc_eim.runtime_profile.v1).
On the NI VeriStand bench, the owner host started by Start-SeccSession.ps1 runs this lane for you with the package's runtime profile; operators do not type this command. The runtime profile fields are described on the NI VeriStand Bench page. Control mode is scheduled only; dynamic is rejected by the runtime.
4. EVCC: probe a real charger (transport and TLS only)
Before attempting a session against a third-party SECC, prove TCP reachability and the mutual TLS 1.3 handshake. The probe deliberately has no session arguments:
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evcc tls-handshake-probe `
--protocol iso15118-20 --profile-id iso15118_20_dc_evcc_reference `
--peer-ipv6 'fe80::<SECC_ADDRESS>%' + $IfIndex --tcp-port 50118 `
--tls --tls-cert "$Pki\vehicle-chain.pem" --tls-key "$Pki\vehicle-key.pem" --tls-cafile "$Pki\v2g-root-ca.pem" --require-ca
Judge the result on the reported status, not on the exit code: the exit code says whether the probe ran, the status says what the SECC decided. The link-local zone index must be this machine's interface index, not the peer's.
5. EVCC: full DC EIM session against a SECC
The live EVCC session refuses to run with hidden defaults: two files delivered in the package's pc2\cases folder must be named through environment variables before evcc activate-profile is started. The EV values in them are test values, not a vehicle implementation.
| Variable | File | Purpose |
|---|---|---|
CHARGELINK_ISO20_LIVE_SEMANTIC_CASE | EV case JSON, for example pc2\cases\nominal.json | The vehicle's identity (EVCCID with Annex C check digit) and electrical parameters: present, precharge and target voltage, target current, power, EV limits, tolerances, safe limits, precharge and charge-loop timeouts. |
CHARGELINK_ISO20_FULL_WIRE_SESSION_MANIFEST | full-wire session manifest, pc2\cases\full-wire-session-manifest.json | Reference encodings against which the EVCC checks its own session. Use the delivered manifest. |
$env:CHARGELINK_ISO20_LIVE_SEMANTIC_CASE = 'C:\ChargeLink\0.5.0-rc2\pc2\cases\nominal.json'
$env:CHARGELINK_ISO20_FULL_WIRE_SESSION_MANIFEST = 'C:\ChargeLink\0.5.0-rc2\pc2\cases\full-wire-session-manifest.json'
# standard flow: SDP discovery on the bench adapter
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evcc activate-profile `
--protocol iso15118-20 --profile-id iso15118_20_dc_evcc_reference `
--use-sdp --interface-index $IfIndex --tcp-port 50118 --exi-mode chargelink-exi `
--tls --tls-cert "$Pki\vehicle-chain.pem" --tls-key "$Pki\vehicle-key.pem" --tls-cafile "$Pki\v2g-root-ca.pem" --require-ca `
--max-steps 14 --requested-power-kw 80
# fallback for transport isolation: direct TCP (no --use-sdp, explicit peer and port)
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evcc activate-profile `
--protocol iso15118-20 --profile-id iso15118_20_dc_evcc_reference `
--peer-ipv6 ('fe80::<SECC_ADDRESS>%' + $IfIndex) --tcp-port 50118 --probe-peer --exi-mode chargelink-exi `
--tls --tls-cert "$Pki\vehicle-chain.pem" --tls-key "$Pki\vehicle-key.pem" --tls-cafile "$Pki\v2g-root-ca.pem" --require-ca `
--max-steps 14 --requested-power-kw 80
Every response wait is bounded by the ISO 15118-20 V2G_EVCC_Msg_Timeout for that message type. The session stays inside the schedule it negotiated; the reference runtime profile offers 60 s. The package's runtime profile offers one 60 s charging schedule; schedule renegotiation is answered when the EV requests it (the SECC never triggers it), so a longer session needs an EV that renegotiates or a profile with a longer schedule.
6. Stop and preserve evidence
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse stop --run-id $Run
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json artifacts inspect --run-id $Run
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json artifacts integrity --run-id $Run
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse live-closure-gate --run-id $Run --source external-evcc `
--require-sdp --require-tcp-peer --require-tls --require-v2gtp --require-exi --write-artifacts
Files to expect in $Data\artifacts\$Run: evse_listener_status.json, evse_runtime_status.json, sdp_diagnostics.json, tls_handshake_diagnostics.json, session_handshake_artifact_gate.json, traces\evse-listener.jsonl, traces\live-v2gtp-frames.jsonl, manifest.json. The closure gate reads them and reports whether SDP, a live TCP peer, TLS, V2GTP exchange and EXI decoding were observed.
What a passing run proves, and what it does not
| Proves | Does not prove |
|---|---|
| IPv6 link-local discovery, TCP, TLS 1.3 mutual authentication, V2GTP framing and EXI decoding with the real peer; message ordering and response budgets; for the plant-coupled lane, protocol decisions correlated with simulated electrical behaviour. | Accredited ISO 15118 conformance; measured isolation (CableCheck is simulated by the plant model); physical PLC/SLAC, control pilot or power hardware; interoperability with vehicles not tested; a live control API (the gRPC GetProtocolState reports unobserved for a stand-alone listener). |
Limits specific to ISO 15118-20: the TLS handshake accepts only the named groups secp521r1 and x448 (peers that offer only P-256 are refused unless the legacy option is given); the plant-coupled lane runs Scheduled or Dynamic control mode as offered by the runtime profile (the package offers Scheduled); in Dynamic mode MobilityNeedsMode 1 and pricing 0 only, available power from a profile script; no SECC-initiated pause or standby; AC and BPT are reference-responder lanes; CertificateInstallation and MeteringConfirmation are not handled by the live EVSE lane; PnC advertisement requires a fixture manifest. See Capability Boundaries.

