ChargeLink

ISO 15118-20

ISO 15118-20 is the second-generation high-level communication protocol for CCS. ChargeLink plays either role: the charger (SECC) for a vehicle or EVCC, or the vehicle (EVCC) for your charger or SECC. It speaks IPv6 link-local SDP, TCP, mutual TLS 1.3, V2GTP and EXI, and runs DC EIM (the full session of 16 request/response pairs from SupportedAppProtocol to SessionStop) and AC EIM (Scheduled and Dynamic control mode). As charger, ChargeLink runs plant-coupled on the NI VeriStand bench: every response is computed from the session state and the simulated power stage of the bench. As vehicle, ChargeLink runs the DC session with evcc activate-profile and the AC session with iso20-ac-evcc.

Before you start

RequirementWhat you need
HardwareA Windows PC for ChargeLink with an Ethernet adapter on the link to the other side. For the charger role: the NI VeriStand bench of the package. A powerline (PLC) link to a vehicle or charger needs the hardware described in Connecting to Real PLC Hardware.
NetworkIPv6 enabled on that adapter; link-local addresses (fe80::/10), no router. UDP 15118 (SDP) and the TCP port of the session (default 50118) open in Windows Firewall for fe80::/10 (Install and Activate). The preflight checks interface index, link-local address, ports and clock.
LicenceAn active ChargeLink licence on the ChargeLink PC (chargelink --json license status). A command that needs it stops with exit code 20 (CL-LICENSE-001).
TLS materialA V2G root CA, plus the chain and key of the side ChargeLink plays: a SECC chain and key when ChargeLink is the charger, a vehicle chain and key when ChargeLink is the vehicle. The other side's material must chain to the same root. See TLS and PKI.
  • TLS 1.3 with mutual authentication is mandatory. ChargeLink rejects plaintext, TLS 1.2 and connections without a verified client certificate before the SupportedAppProtocol exchange. It negotiates only the named groups secp521r1 and x448 and the cipher suites TLS_AES_256_GCM_SHA384 and TLS_CHACHA20_POLY1305_SHA256.
  • Production and engineering material. Production material follows ISO 15118-20 Annex B (ECDSA P-521, SHA-512). evse tls-material-init generates a fresh Annex B-shaped engineering chain on every run; evse start accepts it as the charger identity only with --allow-engineering-tls-identity.
  • Legacy named groups. A peer that offers only other groups (for example P-256 or X25519) is refused before any V2G message. --allow-legacy-tls-named-groups adds secp256r1 after the standard groups; it is an engineering option outside ISO 15118-20, and the charger side then also needs --allow-engineering-tls-identity.
  • The charger identity is validated as an Annex B chain to the V2G root. The DNS name is SNI only; the vehicle-side default --tls-server-name chargelink-secc.local does not need to match a SAN.

Every example on this page uses this block. The kit has a charger\ and a vehicle\ folder; chargelink.exe is the same binary in both.

$CL   = 'C:\Program Files\DEVlink\ChargeLink\<VERSION>\charger\bin\chargelink.exe'
$Data = "$env:ProgramData\DEVlink\ChargeLink\data"
$IfIndex   = <INTERFACE_INDEX>
$Advertise = 'fe80::<ADDRESS>%' + $IfIndex
$Pki       = "$Data\pki"

ChargeLink as charger

The ISO 15118-20 charger runs plant-coupled on the NI VeriStand bench, with profile iso15118_20_dc (DC EIM) or iso15118_20_ac_eim (AC EIM, below). The plant values (voltage, current, contactor, isolation) come from the VeriStand model, and PreCharge, PowerDelivery and the DC charge loop follow the vehicle's targets and the simulated electrical behaviour. The charger is delivered and verified with the ChargeLink vehicle on the VeriStand bench. Contact DEVlink before connecting a third-party vehicle.

The plant-coupled charger session (DC EIM)

On the NI VeriStand bench, the VeriStand operator starts this session for you with the package's runtime profile (ChargeLink Operator (VeriStand), see NI VeriStand Bench); you do not type the command. For reference, the session it starts has this shape:

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 --exi-mode chargelink-exi `
  --plant-grpc-endpoint <BENCH_PLANT_ENDPOINT> --requested-power-kw <kW> --target-voltage-v <V> `
  [--evse-rated-current-a <A>] [--evse-rated-voltage-v <V>] `
  --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
  • --plant-grpc-endpoint is the plant endpoint of the bench; there is no other plant option.
  • --requested-power-kw and --target-voltage-v must be given explicitly (zero means unset and is rejected).
  • The environment variable CHARGELINK_ISO20_RUNTIME_PROFILE points to the runtime profile JSON. The runtime profile sets the control modes offered (Scheduled, Dynamic, or both for the vehicle to choose); the package's runtime profile offers Scheduled. Its fields are described on the NI VeriStand Bench page.
  • --tcp-port 0 picks a free port from 49152–65535; the bound port is reported in the JSON result and in evse_listener_status.json.
  • Do not use --external-evcc-windows-tls or --external-evcc-dev-tls for ISO 15118-20: both select TLS 1.2, which the ISO 15118-20 admission check rejects.
  • ChargeLink enforces its response budget: ChargeLoop 250 ms, ServiceDetail 4500 ms, CableCheck 38 s, other messages 1500 ms. A budget overrun is recorded as a finding.

Watch the session from 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

Network, SDP and TLS check without the bench

evse start without --plant-grpc-endpoint starts a reference responder with fixed reference responses and no plant. It is not a charging session: a vehicle stops early, at AuthorizationSetup. Use it only to check the network, SDP discovery and the TLS 1.3 handshake with the other side.

$Run = "iso20-check-$(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

--external-evcc-session keeps the listener open until --max-runtime-ms elapses or you stop it, and defaults UDP to 15118. The check is good when sdp_diagnostics.json records the SDP exchange and tls_handshake_diagnostics.json a completed TLS 1.3 handshake with the other side's certificate.

This check applies to the DC profile. The AC charger has no check without a plant (see below).

The plant-coupled charger session (AC EIM)

The AC charger runs plant-coupled only, with profile iso15118_20_ac_eim. It needs a plant behind --plant-grpc-endpoint: on the NI VeriStand bench, the bench's plant endpoint. Started without the endpoint, it refuses to start with "protocol-only AC is not offered". The session runs over mutual TLS 1.3 only, as ISO 15118-20 requires; the vehicle must present a certificate chain to the same V2G root. SDP runs on UDP 15118.

$env:CHARGELINK_ISO20_AC_RUNTIME_PROFILE = "$Data\profiles\iso20-ac-charger.json"
Remove-Item Env:\CHARGELINK_ISO20_RUNTIME_PROFILE -ErrorAction SilentlyContinue

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_ac_eim --exi-mode chargelink-exi `
  --plant-grpc-endpoint <BENCH_PLANT_ENDPOINT> --requested-power-kw 11 --target-voltage-v 230 `
  --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
  • --requested-power-kw and --target-voltage-v are required with --plant-grpc-endpoint (zero means unset and is rejected); give the outlet's power and nominal voltage. The AC limits themselves come from the settings file.
  • The environment variable CHARGELINK_ISO20_AC_RUNTIME_PROFILE names the charger's AC settings file. The profile ID and the settings file belong together: either one alone is refused. Do not set the DC variable CHARGELINK_ISO20_RUNTIME_PROFILE in the same window.
  • The kit contains no AC settings file. Write your own, as described below.
  • With engineering TLS material from evse tls-material-init, add --allow-engineering-tls-identity.

The AC settings file

The settings file is JSON. A field the charger does not know is refused.

FieldMeaning
evse_id, parameter_set_idThe charger's EVSEID and the ID of the parameter set it offers.
connector1 single phase, 2 three phase.
nominal_voltage_v, nominal_frequency_hzNominal voltage, phase to neutral (1–500 V), and nominal frequency.
evse_max_current_per_phase_a, cable_rating_aThe power stage's current per phase and the cable rating. The lower of the two is the per-phase limit.
installation_max_power_w (optional)An installation limit below the outlet's power.
evse_minimum_charge_power_wThe minimum charge power the charger states; at least 0 and below the outlet's maximum power.
schedule_tuple_id, schedule_duration_sThe ID and the length of the charging schedule (both above 0).
meter_id, free_serviceThe meter ID (1–32 characters) and whether the service is free.
terminate_notification_max_delay_sThe notification delay the charger states when it terminates the session.
schedule_renegotiation_trigger (optional)true: the charger asks for a new schedule at the schedule's horizon.
dynamic (optional)The Dynamic control mode; see below. Without it, the charger offers the Scheduled control mode only.

The dynamic block:

FieldMeaning
offer_scheduledfalse (default): the charger offers Dynamic only. true: it offers both, Scheduled under parameter_set_id and Dynamic under the next ID, and the vehicle chooses.
policy_modemax_available (default) or departure_spread: how the charger sets the power target.
decision_period_ms, ramp_w_per_s, departure_margin_sHow often the target is recomputed (default 1000 ms), how fast it may change (default 4000 W/s), and the margin before the vehicle's departure time (default 60 s).
available_power_stepsThe available power over time: a list of steps, each with after_ms and power_w.

Example: a three-phase 11 kW charger that offers both control modes.

{
  "evse_id": "<EVSE_ID>",
  "parameter_set_id": 1,
  "connector": 2,
  "nominal_voltage_v": 230,
  "nominal_frequency_hz": 50,
  "evse_max_current_per_phase_a": 16,
  "cable_rating_a": 32,
  "evse_minimum_charge_power_w": 1380,
  "schedule_tuple_id": 1,
  "schedule_duration_s": 3600,
  "meter_id": "<METER_ID>",
  "free_service": true,
  "terminate_notification_max_delay_s": 10,
  "dynamic": {
    "offer_scheduled": true,
    "policy_mode": "max_available",
    "available_power_steps": [ { "after_ms": 0, "power_w": 11000 }, { "after_ms": 60000, "power_w": 7000 } ]
  }
}

Control modes: the charger always offers Scheduled when dynamic is absent; with dynamic it offers Dynamic only, or both when offer_scheduled is true. In both modes the vehicle states its mobility needs (MobilityNeedsMode 1). The charger answers a power tolerance the vehicle confirms with OK_PowerToleranceConfirmed; it offers no tolerance itself.

What a good AC charger session looks like: protocol\iso20_ac_secc_session_evidence.json in the run folder reads "result": "session_stop" and "profile_id": "iso15118_20_ac_eim"; iso20_ac_frames.jsonl beside it has one row per frame, with the response code and response time of each response. evse_listener_status.json reads "status": "stopped" after evse stop.

The DC EIM session at a glance

ISO 15118-20 DC EIM session sequence between EVCC and ChargeLink SECC EVCC (vehicle) ChargeLink SECC Transport Setup and authorization (common namespace) Service and schedule DC energy transfer Stop SDP request (UDP 15118, ff02::1) → response: address, port, security TCP connect → TLS 1.3 handshake, mutual authentication (Annex B chains) SupportedAppProtocolReq → Res (urn:iso:std:iso:15118:-20:DC selected) SessionSetupReq (EVCCID) → Res (EVSEID, SessionID) AuthorizationSetupReq → Res (EIM) · AuthorizationReq → Res budget 1500 ms per response; V2G_EVCC_Msg_Timeout enforced on the vehicle side ServiceDiscoveryReq → Res (DC, service 2) · ServiceDetailReq → Res (parameter set 1) ServiceSelectionReq → Res · DC_ChargeParameterDiscoveryReq → Res (EV / EVSE limits) ScheduleExchangeReq (Scheduled mode) → Res (schedule tuple, 60 s in the reference profile) DC_CableCheckReq → Res Ongoing… Finished (simulated by the plant provider; 38 s deadline) DC_PreChargeReq (target voltage) → Res (present voltage within tolerance) PowerDeliveryReq (Start) → Res · contactor closes in the plant DC_ChargeLoopReq (target current or voltage) → Res (present V/I, limits) · repeated, 250 ms budget orange: values come from the plant model in the plant‑coupled lane; reference vectors otherwise PowerDeliveryReq (Stop) → Res · DC_WeldingDetectionReq → Res · SessionStopReq → Res · TCP held ≥ 5 s
The 16 request/response pairs of an ISO 15118-20 DC EIM session as ChargeLink runs them, with the response budgets it enforces.

What a good session looks like

The run folder is <artifact-root>\<run-id>\. After evse stop:

  • evse_listener_status.json reads "status": "stopped".
  • command_result.json reads "status": "stopped".
  • evse_message_trace.jsonl shows the request/response pairs in order, from SupportedAppProtocol to SessionStop; events.jsonl, diagnostics.json and conformance_traceability.json complete the evidence.
  • The process exits with code 0. The exit code alone is not the verdict: read the status fields.

ChargeLink as vehicle

Your DUT is a charger or SECC. Connect it to the ChargeLink PC's adapter. For DC EIM, the vehicle runs evcc activate-profile with profile iso15118_20_dc_evcc_reference (steps 1 and 2 below). For AC EIM, it runs the iso20-ac-evcc command, which takes no profile (step 3). Contact DEVlink before connecting the DC vehicle to a third-party charger.

Your charger must:

  • offer SDP on the link (or accept a direct TCP connection, see below);
  • offer TLS 1.3 with an ISO 15118-20 Annex B chain on secp521r1 or x448. A P-256 chain is refused unless you add --allow-legacy-tls-named-groups, an engineering option outside ISO 15118-20;
  • chain to the V2G root you pass with --tls-cafile. --tls-server-name sets the expected server name (default chargelink-secc.local).

1. Probe the charger (transport and TLS only)

Prove TCP reachability and the mutual TLS 1.3 handshake first. The probe deliberately takes 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 charger decided. The link-local zone index must be the ChargeLink PC's interface index, not the charger's.

2. Run the DC EIM session

The vehicle session refuses to run with hidden defaults. Name two files from the vehicle folder of the kit (vehicle\cases) in environment variables before you start evcc activate-profile. The EV values in them are test values, not a vehicle implementation.

VariableFilePurpose
CHARGELINK_ISO20_LIVE_SEMANTIC_CASEEV case JSON, for example vehicle\cases\nominal.jsonThe 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_MANIFESTsession manifest, vehicle\cases\full-wire-session-manifest.jsonThe session manifest delivered with the kit. Use it unchanged.
$env:CHARGELINK_ISO20_LIVE_SEMANTIC_CASE        = 'C:\Program Files\DEVlink\ChargeLink\<VERSION>\vehicle\cases\nominal.json'
$env:CHARGELINK_ISO20_FULL_WIRE_SESSION_MANIFEST = 'C:\Program Files\DEVlink\ChargeLink\<VERSION>\vehicle\cases\full-wire-session-manifest.json'

# standard flow: SDP discovery on the adapter to the charger
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 <CHARGER_TLS_PORT> --exi-mode chargelink-exi `
  --tls --tls-cert "$Pki\vehicle-chain.pem" --tls-key "$Pki\vehicle-key.pem" --tls-cafile "<V2G_ROOT_OF_THE_CHARGER_CHAIN>" --require-ca `
  --max-steps 14 --requested-power-kw 80

# to isolate transport problems: 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 <CHARGER_TLS_PORT> --probe-peer --exi-mode chargelink-exi `
  --tls --tls-cert "$Pki\vehicle-chain.pem" --tls-key "$Pki\vehicle-key.pem" --tls-cafile "<V2G_ROOT_OF_THE_CHARGER_CHAIN>" --require-ca `
  --max-steps 14 --requested-power-kw 80

--interface-index is the ChargeLink PC's interface to the charger. Every response wait is bounded by the ISO 15118-20 V2G_EVCC_Msg_Timeout for that message type. The vehicle stays inside the schedule it negotiated with the charger.

What a good session looks like

The run folder is <artifact-root>\cl-evcc-<id>\ (the JSON result names it):

  • summary.json reads "status": "passed" and "session_stopped": true, and observed_state_count equals required_state_count (16 of 16 for a nominal DC session).
  • command_result.json reads "status": "stopped".
  • protocol_summary.json, protocol_session.json, the traces (evcc_message_trace.jsonl and .log, frames.jsonl, trace.jsonl), events.jsonl, diagnostics.json, manifest.json and conformance_traceability.json complete the evidence.
  • The process exits with code 0. The exit code alone is not the verdict: read the status fields.

3. Run the AC EIM session

iso20-ac-evcc runs one ISO 15118-20 AC EIM session against your charger: SDP, mutual TLS 1.3 with the vehicle certificate chain, then one V2G communication session. It selects the AC service (ServiceID 1) and the offered parameter set whose control mode matches its own and whose mobility needs mode is 1. If the charger offers no matching set, the vehicle stops at once with SessionStopReq (Terminate).

# standard flow: SDP discovery
chargelink iso20-ac-evcc --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json `
  --sdp-server ('[fe80::<SECC_ADDRESS>%' + $IfIndex + ']:15118') `
  --tls-cert "$Pki\vehicle-chain.pem" --tls-key "$Pki\vehicle-key.pem" --tls-root "<V2G_ROOT_OF_THE_CHARGER_CHAIN>" `
  --phases 3 --ev-max-power-w 11000 --ev-min-power-w 1400 --charge-loops 20

# without SDP: the charger's TLS port
chargelink iso20-ac-evcc --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json `
  --peer ('[fe80::<SECC_ADDRESS>%' + $IfIndex + ']:50118') `
  --tls-cert "$Pki\vehicle-chain.pem" --tls-key "$Pki\vehicle-key.pem" --tls-root "<V2G_ROOT_OF_THE_CHARGER_CHAIN>"

The kit contains no AC vehicle case files. Describe the vehicle with the options below, or with --case <FILE>, a JSON case file with the EV settings it names over the defaults (a field the vehicle does not know is refused; with --case, the EV options below are not used). The Dynamic control mode is selected in a case file, with "control_mode": "dynamic"; without it the vehicle uses the Scheduled control mode.

OptionMeaning
--sdp-server <ADDR>The charger's SDP socket, for example [fe80::1%12]:15118. The zone index is the ChargeLink PC's interface index.
--peer <ADDR>Without SDP: the charger's TLS port, for example [fe80::1%12]:50118. Give either --sdp-server or --peer.
--tls-cert, --tls-key, --tls-rootRequired: the vehicle certificate chain (PEM, leaf first), its private key, and the V2G root the charger's chain must end in.
--tls-server-name, --iso20-curve-profile, --allow-legacy-tls-named-groupsAs for the DC vehicle: the expected server name (default chargelink-secc.local), the preferred named group (secp521r1 or x448), and the engineering option for P-256 test peers.
--phasesThe phases the vehicle's charger uses: 1 or 3 (default 3).
--ev-max-power-w, --ev-min-power-wThe vehicle's maximum and minimum charge power as the sum over the phases (defaults 11000 W and 1400 W).
--per-phase-cpdSends per-phase values in AC_ChargeParameterDiscoveryReq, for an asymmetric vehicle.
--charge-loops, --energy-target-whThe number of AC_ChargeLoopReqs before the vehicle stops (default 20; 0 runs until the energy target or a charger stop), and an energy target in Wh.
--loop-period-ms, --meter-info-every, --no-loop-limitsThe pause between charge-loop messages (below 250 ms, default 100 ms); MeterInfoRequested on every n-th charge-loop request; leave the power limits out of the charge-loop request.
--renegotiate-afterThe vehicle asks once for a new schedule after this many charge-loop requests.
--standby-after, --pauseOnce, after this many charge-loop requests, a PowerDeliveryReq with ChargeProgress Standby; a SessionStopReq with Pause instead of Terminate. Use them to test your charger's answer.
--fault with --qualification-onlyOne faulty request to test your charger's handling: invalid_cpd, loop_maximum_above_cpd, per_phase_in_loop or dynamic_branch_in_scheduled. --qualification-only marks the run as a test case; a normal session refuses request faults.
--connect-timeout-ms, --run-idThe connection timeout (default 2000 ms) and your run identifier.

The vehicle confirms the power tolerance of the schedule it selected in every PowerDeliveryReq. Per-phase values that the charger sends without the vehicle having asked for them are ignored and recorded; the vehicle goes on with the base values.

What a good AC session looks like

  • The run folder is <artifact-root>\<run-id>\; without --run-id it is named iso20-ac-evcc-<number>, which the JSON result names.
  • iso20_ac_evcc_report.json reads "passed": true. The command fails unless the session ended with SessionStopRes (or with your charger's FAILED answer to the fault the run asked for).
  • traces\live-v2gtp-frames.jsonl holds one row per frame.

Results and evidence

Each run writes one folder under the artifact root: $Data\artifacts\<run-id>. Charger runs use the --run-id you pass; vehicle runs without one get a generated ID (cl-evcc-<id> for DC, iso20-ac-evcc-<number> for AC) that the JSON result names. For AC, the charger's session record is protocol\iso20_ac_secc_session_evidence.json with the frame list iso20_ac_frames.jsonl, and the vehicle's verdict is iso20_ac_evcc_report.json. Stop the charger, then check the 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

evse live-closure-gate reads the charger's run folder and reports whether SDP, a live TCP peer, TLS, V2GTP exchange and EXI decoding were observed. artifacts integrity confirms that no file changed after the run. Every artifact carries a claim boundary: it is engineering evidence, not certification. See Trace, Evidence and Reports.

A passing run showsA passing run does not show
IPv6 link-local discovery, TCP, TLS 1.3 mutual authentication, V2GTP framing and EXI decoding with the other side; message ordering and response times; for the plant-coupled charger session, 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 or chargers not tested; a live control API (the gRPC GetProtocolState reports unobserved for a stand-alone listener).

Limits

  • EIM only. ChargeLink does not provide bidirectional power transfer (BPT) or Plug & Charge (Contract authorization): evse start refuses a profile whose ID names either (for example bpt, bidirectional, v2g, pnc, contract or plug) with exit code 70 (CL-UNSUPPORTED-001) before any socket opens.
  • The TLS handshake accepts only the named groups secp521r1 and x448, unless --allow-legacy-tls-named-groups is given.
  • The charging session of the charger role runs plant-coupled on the NI VeriStand bench; there is no other plant option. The charger is delivered and verified with the ChargeLink vehicle on the VeriStand bench. In DEVlink's own tests, ChargeLink's charger has also completed ISO 15118-20 DC sessions over Ethernet with a third-party vehicle stack; this has not been verified on the VeriStand bench. Connecting a real vehicle needs a physical layer (control pilot, PLC) that this release does not include. Contact DEVlink before connecting a third-party vehicle.
  • Without --plant-grpc-endpoint, the DC charger is a reference responder with fixed responses and no plant. It is not a charging session; use it only to check the network, SDP and TLS. The AC charger does not start without a plant.
  • AC: one charger that offers AC and DC together is not available; the AC charger runs under iso15118_20_ac_eim with its AC settings file, the DC charger under iso15118_20_dc.
  • AC: the Dynamic control mode has been shown with the charger and the vehicle on one PC. On the NI VeriStand bench with the vehicle on a second PC, use the Scheduled control mode.
  • AC: mobility needs mode 1 only (the vehicle states its needs). A charger that offers only mode 2 is stopped by the ChargeLink vehicle (Terminate) after ServiceDetailRes.
  • AC: not offered are charger-initiated pause, service renegotiation, standby and pricing. The AC charger offers no power tolerance in its schedules; it answers a missing or unconfirmed tolerance with OK and records it.
  • AC: a V2GTP frame with a wrong header ends the AC session on both sides instead of being ignored while the message timer runs; a wrong payload length also ends the session on a decode or timer error. Not safety-relevant.
  • AC: faults inside the charger, such as a residual-current trip that opens the contactor, end the session through the charger's stop path, or the charger answers FAILED and contains the session; this behaviour is shown by DEVlink's own tests. The schema validity of each AC message is not checked during a run; it is covered by the AC codec's test vectors.
  • Dynamic control mode supports MobilityNeedsMode 1 and pricing 0 only, with available power from a profile script. The charger never pauses or enters standby on its own.
  • The package's runtime profile offers one 60 s charging schedule. Schedule renegotiation is answered when the vehicle requests it; the charger never triggers it. A longer session needs a vehicle that renegotiates or a runtime profile with a longer schedule.
  • The charger does not handle CertificateInstallation or MeteringConfirmation.
  • As vehicle, ChargeLink runs a live DC session with the profile iso15118_20_dc_evcc_reference and the EV case files of the kit; contact DEVlink before connecting the DC vehicle to a third-party charger. The live AC session runs with iso20-ac-evcc; the kit ships no AC vehicle case files, so you describe the vehicle with the command's options or your own case file.
  • No physical charging interface (PLC, control pilot, power stage) is included.

See Capability Boundaries for every standard. To check the installation without a DUT, see Self-test without a device under test.

Troubleshooting

SymptomUsually meansAction
TCP connects, then the connection closes before SupportedAppProtocolThe peer offered plaintext, TLS 1.2 or no client certificateUse TLS 1.3 with mutual authentication on both sides; check tls_handshake_diagnostics.json.
Handshake refused with a P-256 or X25519 peerThe peer offers no secp521r1 or x448 groupGive the peer an Annex B identity, or add --allow-legacy-tls-named-groups (and --allow-engineering-tls-identity on the charger side) as an engineering option.
evse start refuses the TLS identityEngineering material from evse tls-material-initAdd --allow-engineering-tls-identity, or use production material.
TLS fails with a valid-looking chainThe chain does not lead to the shared V2G root, or the clock is wrongSee TLS and PKI; run evse tls-pki-doctor and check w32tm /query /status.
Exit 70, CL-UNSUPPORTED-001 at evse startThe profile ID names BPT or Plug & ChargeUse an EIM profile such as iso15118_20_dc.
TLS 1.2 rejected by the admission check--external-evcc-windows-tls or --external-evcc-dev-tls was givenRemove the option; ISO 15118-20 uses the default TLS adapter with TLS 1.3.
The vehicle stops at AuthorizationSetupThe charger was started without --plant-grpc-endpoint (reference responder)Expected: the reference responder checks network, SDP and TLS only. Run the charging session plant-coupled on the NI VeriStand bench.
evcc activate-profile refuses to startAn EV case variable is not set or names a missing fileSet CHARGELINK_ISO20_LIVE_SEMANTIC_CASE and CHARGELINK_ISO20_FULL_WIRE_SESSION_MANIFEST to the kit files.
The AC charger refuses to start: "protocol-only AC is not offered"iso15118_20_ac_eim was started without --plant-grpc-endpointStart it plant-coupled, with the bench's plant endpoint, --requested-power-kw and --target-voltage-v.
The AC charger refuses its configurationCHARGELINK_ISO20_AC_RUNTIME_PROFILE is missing, the DC variable is also set, or the settings file has an unknown or invalid fieldSet only the AC variable, to a settings file with the fields above; the error message names the field.
iso20-ac-evcc stops right after the service exchange with SessionStopReq (Terminate)Your charger offers no parameter set with the vehicle's control mode and mobility needs mode 1Offer a matching parameter set, or select the other control mode in a case file.
iso20-ac-evcc refuses to start: "give --sdp-server or --peer"No charger address was givenAdd --sdp-server (SDP) or --peer (the TLS port).
"unreachable network" (10051) on the vehicle sideThe peer address carries the charger's zone indexUse fe80::<peer>%<LOCAL_INDEX>.
A response-time finding in the evidenceA response exceeded its budgetFind the message in the message trace; check CPU load and other traffic on the PC.
The plant-coupled session ends after about 60 sThe runtime profile offers one 60 s scheduleLet the vehicle renegotiate, or use a runtime profile with a longer schedule.
The plant-coupled session is rejected at start--requested-power-kw or --target-voltage-v is zero (unset)Give both values explicitly, with CHARGELINK_ISO20_RUNTIME_PROFILE set; on the VeriStand bench, start the session from the VeriStand operator (NI VeriStand Bench).

General failures (licence, ports, firewall, role locks) are in Troubleshooting.